From c1a9b12dc94607f2d0cec7929de9ba4c085f47f1 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 19 Sep 2015 14:38:37 +0200 Subject: [PATCH] Imported Upstream version 1.3.0+dfsg1 --- AUTHORS.txt | 52 +- CONTRIBUTING.md | 23 +- Makefile.in | 3 +- README.md | 4 +- RELEASES.md | 228 +- configure | 245 +- mk/cfg/aarch64-linux-android.mk | 8 +- mk/cfg/arm-linux-androideabi.mk | 8 +- mk/cfg/i686-pc-windows-msvc.mk | 29 + mk/cfg/i686-unknown-freebsd.mk | 22 + mk/cfg/x86_64-pc-windows-msvc.mk | 68 +- mk/cfg/x86_64-unknown-netbsd.mk | 22 + mk/ctags.mk | 23 +- mk/docs.mk | 9 +- mk/main.mk | 5 +- mk/platform.mk | 53 + mk/rt.mk | 28 +- mk/rustllvm.mk | 3 +- mk/target.mk | 35 + mk/tests.mk | 3 +- src/compiletest/compiletest.rs | 6 +- src/compiletest/runtest.rs | 28 +- src/compiletest/util.rs | 1 + src/doc/complement-design-faq.md | 2 +- src/doc/guide-pointers.md | 9 +- src/doc/index.md | 14 +- src/doc/nomicon/README.md | 38 + src/doc/nomicon/SUMMARY.md | 53 + src/doc/nomicon/arc-and-mutex.md | 7 + src/doc/nomicon/atomics.md | 255 + src/doc/nomicon/borrow-splitting.md | 291 + src/doc/nomicon/casts.md | 71 + src/doc/nomicon/checked-uninit.md | 117 + src/doc/nomicon/coercions.md | 70 + src/doc/nomicon/concurrency.md | 13 + src/doc/nomicon/constructors.md | 59 + src/doc/nomicon/conversions.md | 34 + src/doc/nomicon/data.md | 5 + src/doc/nomicon/destructors.md | 181 + src/doc/nomicon/dot-operator.md | 6 + src/doc/nomicon/drop-flags.md | 95 + src/doc/nomicon/dropck.md | 127 + src/doc/nomicon/exception-safety.md | 217 + src/doc/nomicon/exotic-sizes.md | 137 + src/doc/nomicon/hrtb.md | 73 + src/doc/nomicon/leaking.md | 252 + src/doc/nomicon/lifetime-elision.md | 64 + src/doc/nomicon/lifetime-mismatch.md | 81 + src/doc/nomicon/lifetimes.md | 215 + src/doc/nomicon/meet-safe-and-unsafe.md | 98 + src/doc/nomicon/obrm.md | 14 + src/doc/nomicon/other-reprs.md | 76 + src/doc/nomicon/ownership.md | 67 + src/doc/nomicon/phantom-data.md | 87 + src/doc/nomicon/poisoning.md | 35 + src/doc/nomicon/races.md | 86 + src/doc/nomicon/references.md | 177 + src/doc/nomicon/repr-rust.md | 152 + src/doc/nomicon/safe-unsafe-meaning.md | 150 + src/doc/nomicon/send-and-sync.md | 80 + src/doc/nomicon/subtyping.md | 212 + src/doc/nomicon/transmutes.md | 35 + src/doc/nomicon/unbounded-lifetimes.md | 37 + src/doc/nomicon/unchecked-uninit.md | 85 + src/doc/nomicon/uninitialized.md | 10 + src/doc/nomicon/unwinding.md | 49 + src/doc/nomicon/vec-alloc.md | 222 + src/doc/nomicon/vec-dealloc.md | 29 + src/doc/nomicon/vec-deref.md | 42 + src/doc/nomicon/vec-drain.md | 150 + src/doc/nomicon/vec-final.md | 311 + src/doc/nomicon/vec-insert-remove.md | 51 + src/doc/nomicon/vec-into-iter.md | 147 + src/doc/nomicon/vec-layout.md | 100 + src/doc/nomicon/vec-push-pop.md | 55 + src/doc/nomicon/vec-raw.md | 136 + src/doc/nomicon/vec-zsts.md | 176 + src/doc/nomicon/vec.md | 20 + src/doc/nomicon/working-with-unsafe.md | 119 + src/doc/reference.md | 223 +- src/doc/rust.css | 4 + src/doc/style/features/traits/generics.md | 2 +- src/doc/trpl/SUMMARY.md | 6 +- src/doc/trpl/academic-research.md | 37 +- src/doc/trpl/advanced-linking.md | 151 + src/doc/trpl/choosing-your-guarantees.md | 359 + src/doc/trpl/comments.md | 11 + src/doc/trpl/compiler-plugins.md | 5 +- src/doc/trpl/concurrency.md | 23 +- src/doc/trpl/crates-and-modules.md | 7 +- src/doc/trpl/dining-philosophers.md | 30 +- src/doc/trpl/documentation.md | 12 +- src/doc/trpl/error-handling.md | 4 +- src/doc/trpl/ffi.md | 29 +- src/doc/trpl/for-loops.md | 85 - src/doc/trpl/glossary.md | 58 +- src/doc/trpl/guessing-game.md | 14 +- src/doc/trpl/hello-cargo.md | 36 +- src/doc/trpl/hello-world.md | 11 +- src/doc/trpl/inline-assembly.md | 11 +- src/doc/trpl/installing-rust.md | 21 +- src/doc/trpl/intrinsics.md | 2 +- src/doc/trpl/lang-items.md | 1 + src/doc/trpl/lifetimes.md | 29 + src/doc/trpl/link-args.md | 25 - src/doc/trpl/loops.md | 209 + src/doc/trpl/no-stdlib.md | 3 + src/doc/trpl/ownership.md | 4 +- src/doc/trpl/patterns.md | 47 +- src/doc/trpl/references-and-borrowing.md | 7 +- src/doc/trpl/release-channels.md | 23 + src/doc/trpl/testing.md | 5 +- src/doc/trpl/the-stack-and-the-heap.md | 8 +- src/doc/trpl/traits.md | 32 +- src/doc/trpl/unsafe.md | 58 +- src/doc/trpl/while-loops.md | 93 - src/etc/ctags.rust | 6 +- src/etc/debugger_pretty_printers_common.py | 16 +- src/etc/errorck.py | 22 + src/etc/mklldeps.py | 13 +- src/etc/snapshot.py | 11 +- src/etc/snapshot.pyc | Bin 10137 -> 0 bytes src/etc/unicode.py | 10 - src/jemalloc/VERSION | 2 +- src/liballoc/arc.rs | 302 +- src/liballoc/boxed.rs | 194 +- src/liballoc/boxed_test.rs | 8 +- src/liballoc/lib.rs | 22 +- src/liballoc/raw_vec.rs | 453 ++ src/liballoc/rc.rs | 57 +- src/libcollections/binary_heap.rs | 24 +- src/libcollections/bit.rs | 154 +- src/libcollections/borrow.rs | 4 +- src/libcollections/btree/map.rs | 6 +- src/libcollections/btree/set.rs | 3 +- src/libcollections/fmt.rs | 67 +- src/libcollections/lib.rs | 13 +- src/libcollections/linked_list.rs | 6 +- src/libcollections/slice.rs | 87 +- src/libcollections/str.rs | 285 +- src/libcollections/string.rs | 99 +- src/libcollections/vec.rs | 385 +- src/libcollections/vec_deque.rs | 459 +- src/libcollections/vec_map.rs | 70 +- src/libcollectionstest/lib.rs | 9 +- src/libcollectionstest/slice.rs | 138 +- src/libcollectionstest/str.rs | 68 +- src/libcollectionstest/string.rs | 16 +- src/libcollectionstest/vec.rs | 21 - src/libcore/any.rs | 4 +- src/libcore/array.rs | 3 +- src/libcore/atomic.rs | 81 +- src/libcore/cell.rs | 20 +- src/libcore/char.rs | 29 +- src/libcore/cmp.rs | 16 +- src/libcore/fmt/builders.rs | 6 + src/libcore/fmt/mod.rs | 374 +- src/libcore/fmt/num.rs | 93 +- src/libcore/hash/mod.rs | 31 +- src/libcore/hash/sip.rs | 28 +- src/libcore/intrinsics.rs | 17 +- src/libcore/iter.rs | 46 +- src/libcore/lib.rs | 36 +- src/libcore/macros.rs | 4 +- src/libcore/marker.rs | 2 +- src/libcore/mem.rs | 122 +- src/libcore/num/f32.rs | 72 +- src/libcore/num/f64.rs | 12 +- src/libcore/num/i16.rs | 1 - src/libcore/num/i32.rs | 1 - src/libcore/num/i64.rs | 1 - src/libcore/num/i8.rs | 1 - src/libcore/num/int_macros.rs | 4 + src/libcore/num/isize.rs | 1 - src/libcore/num/mod.rs | 56 +- src/libcore/num/u16.rs | 1 - src/libcore/num/u32.rs | 1 - src/libcore/num/u64.rs | 1 - src/libcore/num/u8.rs | 1 - src/libcore/num/uint_macros.rs | 4 + src/libcore/num/usize.rs | 1 - src/libcore/num/wrapping.rs | 10 + src/libcore/ops.rs | 194 +- src/libcore/option.rs | 33 +- src/libcore/ptr.rs | 84 +- src/libcore/raw.rs | 6 +- src/libcore/result.rs | 5 +- src/libcore/simd.rs | 3 +- src/libcore/slice.rs | 76 +- src/libcore/str/mod.rs | 414 +- src/libcore/str/pattern.rs | 719 +- src/libcore/tuple.rs | 3 +- src/libcoretest/char.rs | 23 - src/libcoretest/fmt/num.rs | 2 - src/libcoretest/hash/mod.rs | 2 + src/libcoretest/hash/sip.rs | 216 +- src/libcoretest/num/mod.rs | 11 +- src/libcoretest/ptr.rs | 5 +- src/libfmt_macros/lib.rs | 2 +- src/libgetopts/lib.rs | 8 +- src/libgraphviz/lib.rs | 201 +- src/liblibc/lib.rs | 195 +- src/librand/distributions/range.rs | 1 + src/librand/isaac.rs | 1 - src/librand/lib.rs | 1 + src/librand/reseeding.rs | 2 +- src/librustc/ast_map/mod.rs | 205 +- src/librustc/diagnostics.rs | 959 ++- src/librustc/lib.rs | 15 +- src/librustc/lint/context.rs | 59 +- src/librustc/metadata/creader.rs | 28 +- src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/cstore.rs | 4 +- src/librustc/metadata/decoder.rs | 39 +- src/librustc/metadata/encoder.rs | 103 +- src/librustc/metadata/loader.rs | 5 +- src/librustc/metadata/macro_import.rs | 8 +- src/librustc/metadata/tydecode.rs | 70 +- src/librustc/metadata/tyencode.rs | 29 +- src/librustc/middle/astconv_util.rs | 8 +- src/librustc/middle/astencode.rs | 232 +- src/librustc/middle/cast.rs | 8 +- src/librustc/middle/cfg/construct.rs | 17 +- src/librustc/middle/check_const.rs | 99 +- src/librustc/middle/check_match.rs | 123 +- src/librustc/middle/check_rvalues.rs | 10 +- src/librustc/middle/check_static_recursion.rs | 200 +- src/librustc/middle/const_eval.rs | 265 +- src/librustc/middle/dataflow.rs | 13 +- src/librustc/middle/dead.rs | 57 +- src/librustc/middle/def.rs | 24 +- src/librustc/middle/effect.rs | 71 +- src/librustc/middle/expr_use_visitor.rs | 142 +- src/librustc/middle/fast_reject.rs | 6 +- src/librustc/middle/free_region.rs | 31 +- src/librustc/middle/implicator.rs | 94 +- src/librustc/middle/infer/bivariate.rs | 9 +- src/librustc/middle/infer/combine.rs | 24 +- src/librustc/middle/infer/equate.rs | 5 - src/librustc/middle/infer/error_reporting.rs | 402 +- src/librustc/middle/infer/freshen.rs | 6 +- src/librustc/middle/infer/glb.rs | 10 - .../middle/infer/higher_ranked/README.md | 12 +- .../middle/infer/higher_ranked/mod.rs | 23 +- src/librustc/middle/infer/lub.rs | 5 - src/librustc/middle/infer/mod.rs | 562 +- .../middle/infer/region_inference/README.md | 18 +- .../middle/infer/region_inference/mod.rs | 65 +- src/librustc/middle/infer/resolve.rs | 18 +- src/librustc/middle/infer/sub.rs | 18 +- src/librustc/middle/infer/type_variable.rs | 71 +- src/librustc/middle/infer/unify_key.rs | 6 +- src/librustc/middle/intrinsicck.rs | 29 +- src/librustc/middle/lang_items.rs | 7 + src/librustc/middle/liveness.rs | 37 +- src/librustc/middle/mem_categorization.rs | 94 +- src/librustc/middle/pat_util.rs | 2 +- src/librustc/middle/reachable.rs | 7 +- src/librustc/middle/resolve_lifetime.rs | 39 +- src/librustc/middle/stability.rs | 127 +- src/librustc/middle/subst.rs | 37 +- src/librustc/middle/traits/README.md | 76 +- src/librustc/middle/traits/coherence.rs | 15 +- src/librustc/middle/traits/error_reporting.rs | 24 +- src/librustc/middle/traits/fulfill.rs | 70 +- src/librustc/middle/traits/mod.rs | 54 +- src/librustc/middle/traits/object_safety.rs | 18 +- src/librustc/middle/traits/project.rs | 46 +- src/librustc/middle/traits/select.rs | 302 +- src/librustc/middle/traits/util.rs | 112 +- src/librustc/middle/ty.rs | 7147 ++++++++--------- src/librustc/middle/ty_fold.rs | 100 +- src/librustc/middle/ty_match.rs | 7 +- src/librustc/middle/ty_relate/mod.rs | 121 +- src/librustc/middle/ty_walk.rs | 8 +- src/librustc/middle/weak_lang_items.rs | 7 +- src/librustc/session/config.rs | 18 +- src/librustc/session/mod.rs | 6 +- src/librustc/util/common.rs | 80 +- src/librustc/util/ppaux.rs | 107 +- src/librustc_back/archive.rs | 361 - src/librustc_back/arm.rs | 77 - src/librustc_back/lib.rs | 7 - src/librustc_back/mips.rs | 72 - src/librustc_back/mipsel.rs | 72 - src/librustc_back/sha2.rs | 6 +- src/librustc_back/svh.rs | 28 +- src/librustc_back/target/aarch64_apple_ios.rs | 4 - .../target/aarch64_linux_android.rs | 3 - .../target/aarch64_unknown_linux_gnu.rs | 3 - src/librustc_back/target/apple_base.rs | 1 + .../target/arm_linux_androideabi.rs | 3 - .../target/arm_unknown_linux_gnueabi.rs | 5 - .../target/arm_unknown_linux_gnueabihf.rs | 5 - src/librustc_back/target/armv7_apple_ios.rs | 1 - src/librustc_back/target/armv7s_apple_ios.rs | 1 - src/librustc_back/target/bitrig_base.rs | 3 +- src/librustc_back/target/dragonfly_base.rs | 1 + src/librustc_back/target/freebsd_base.rs | 1 + src/librustc_back/target/i386_apple_ios.rs | 5 - src/librustc_back/target/i686_apple_darwin.rs | 5 - .../target/i686_pc_windows_gnu.rs | 1 - .../target/i686_pc_windows_msvc.rs | 26 + .../target/i686_unknown_dragonfly.rs | 1 - .../target/i686_unknown_freebsd.rs | 28 + .../target/i686_unknown_linux_gnu.rs | 1 - src/librustc_back/target/linux_base.rs | 1 + .../target/mips_unknown_linux_gnu.rs | 5 - .../target/mipsel_unknown_linux_gnu.rs | 5 - src/librustc_back/target/mod.rs | 25 +- src/librustc_back/target/netbsd_base.rs | 33 + src/librustc_back/target/openbsd_base.rs | 1 + .../target/powerpc_unknown_linux_gnu.rs | 1 - src/librustc_back/target/windows_base.rs | 1 + .../target/x86_64_apple_darwin.rs | 3 - src/librustc_back/target/x86_64_apple_ios.rs | 3 - .../target/x86_64_pc_windows_gnu.rs | 5 +- .../target/x86_64_pc_windows_msvc.rs | 7 - .../target/x86_64_unknown_bitrig.rs | 3 - .../target/x86_64_unknown_dragonfly.rs | 3 - .../target/x86_64_unknown_freebsd.rs | 3 - .../target/x86_64_unknown_linux_gnu.rs | 3 - .../target/x86_64_unknown_linux_musl.rs | 3 - .../target/x86_64_unknown_netbsd.rs | 26 + .../target/x86_64_unknown_openbsd.rs | 3 - src/librustc_back/x86.rs | 58 - src/librustc_back/x86_64.rs | 62 - src/librustc_bitflags/lib.rs | 6 +- src/librustc_borrowck/borrowck/check_loans.rs | 224 +- src/librustc_borrowck/borrowck/fragments.rs | 96 +- .../borrowck/gather_loans/gather_moves.rs | 4 +- .../borrowck/gather_loans/lifetime.rs | 2 +- .../borrowck/gather_loans/mod.rs | 164 +- .../borrowck/gather_loans/move_error.rs | 2 +- .../borrowck/gather_loans/restrictions.rs | 2 +- src/librustc_borrowck/borrowck/mod.rs | 91 +- src/librustc_borrowck/borrowck/move_data.rs | 4 + src/librustc_borrowck/diagnostics.rs | 74 +- src/librustc_data_structures/bitvec.rs | 4 +- src/librustc_data_structures/unify/mod.rs | 8 +- src/librustc_driver/driver.rs | 30 +- src/librustc_driver/lib.rs | 49 +- src/librustc_driver/pretty.rs | 8 +- src/librustc_driver/test.rs | 106 +- src/librustc_lint/builtin.rs | 663 +- src/librustc_lint/lib.rs | 3 + src/librustc_llvm/archive_ro.rs | 68 +- src/librustc_llvm/lib.rs | 51 +- src/librustc_privacy/lib.rs | 82 +- src/librustc_resolve/build_reduced_graph.rs | 60 +- src/librustc_resolve/diagnostics.rs | 467 +- src/librustc_resolve/lib.rs | 730 +- src/librustc_resolve/record_exports.rs | 3 +- src/librustc_resolve/resolve_imports.rs | 59 +- src/librustc_trans/back/archive.rs | 511 ++ src/librustc_trans/back/link.rs | 339 +- src/librustc_trans/back/linker.rs | 63 +- src/librustc_trans/back/lto.rs | 61 +- src/librustc_trans/back/msvc/mod.rs | 332 + src/librustc_trans/back/msvc/registry.rs | 171 + src/librustc_trans/back/write.rs | 322 +- src/librustc_trans/lib.rs | 12 +- src/librustc_trans/save/dump_csv.rs | 361 +- src/librustc_trans/save/mod.rs | 318 +- src/librustc_trans/save/span_utils.rs | 7 + src/librustc_trans/trans/_match.rs | 436 +- src/librustc_trans/trans/adt.rs | 72 +- src/librustc_trans/trans/asm.rs | 2 +- src/librustc_trans/trans/attributes.rs | 19 +- src/librustc_trans/trans/base.rs | 458 +- src/librustc_trans/trans/build.rs | 8 +- src/librustc_trans/trans/builder.rs | 18 +- src/librustc_trans/trans/cabi_x86_64.rs | 3 +- src/librustc_trans/trans/callee.rs | 281 +- src/librustc_trans/trans/cleanup.rs | 134 +- src/librustc_trans/trans/closure.rs | 129 +- src/librustc_trans/trans/common.rs | 392 +- src/librustc_trans/trans/consts.rs | 725 +- src/librustc_trans/trans/context.rs | 67 +- src/librustc_trans/trans/datum.rs | 177 +- src/librustc_trans/trans/debuginfo/gdb.rs | 1 - .../trans/debuginfo/metadata.rs | 173 +- src/librustc_trans/trans/debuginfo/mod.rs | 77 +- .../trans/debuginfo/namespace.rs | 11 +- .../trans/debuginfo/type_names.rs | 25 +- src/librustc_trans/trans/declare.rs | 33 +- src/librustc_trans/trans/expr.rs | 240 +- src/librustc_trans/trans/foreign.rs | 33 +- src/librustc_trans/trans/glue.rs | 69 +- src/librustc_trans/trans/inline.rs | 11 +- src/librustc_trans/trans/intrinsic.rs | 313 +- src/librustc_trans/trans/llrepr.rs | 2 +- src/librustc_trans/trans/machine.rs | 14 +- src/librustc_trans/trans/meth.rs | 254 +- src/librustc_trans/trans/monomorphize.rs | 43 +- src/librustc_trans/trans/tvec.rs | 16 +- src/librustc_trans/trans/type_.rs | 7 +- src/librustc_trans/trans/type_of.rs | 62 +- src/librustc_typeck/astconv.rs | 438 +- src/librustc_typeck/check/_match.rs | 98 +- src/librustc_typeck/check/assoc.rs | 8 +- src/librustc_typeck/check/callee.rs | 19 +- src/librustc_typeck/check/cast.rs | 51 +- src/librustc_typeck/check/closure.rs | 45 +- src/librustc_typeck/check/coercion.rs | 20 +- src/librustc_typeck/check/compare_method.rs | 64 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/dropck.rs | 473 +- src/librustc_typeck/check/method/confirm.rs | 167 +- src/librustc_typeck/check/method/mod.rs | 90 +- src/librustc_typeck/check/method/probe.rs | 336 +- src/librustc_typeck/check/method/suggest.rs | 33 +- src/librustc_typeck/check/mod.rs | 1339 +-- src/librustc_typeck/check/op.rs | 74 +- src/librustc_typeck/check/regionck.rs | 128 +- src/librustc_typeck/check/upvar.rs | 177 +- src/librustc_typeck/check/wf.rs | 100 +- src/librustc_typeck/check/writeback.rs | 57 +- src/librustc_typeck/coherence/mod.rs | 82 +- src/librustc_typeck/coherence/orphan.rs | 23 +- src/librustc_typeck/coherence/overlap.rs | 16 +- src/librustc_typeck/coherence/unsafety.rs | 4 +- src/librustc_typeck/collect.rs | 299 +- .../constrained_type_params.rs | 2 +- src/librustc_typeck/diagnostics.rs | 1179 ++- src/librustc_typeck/lib.rs | 37 +- src/librustc_typeck/rscope.rs | 79 +- src/librustc_typeck/variance.rs | 24 +- src/librustc_unicode/char.rs | 58 +- src/librustc_unicode/tables.rs | 520 -- src/librustc_unicode/u_str.rs | 3 +- src/librustdoc/clean/inline.rs | 38 +- src/librustdoc/clean/mod.rs | 42 +- src/librustdoc/clean/simplify.rs | 5 +- src/librustdoc/flock.rs | 1 + src/librustdoc/html/format.rs | 15 +- src/librustdoc/html/highlight.rs | 4 +- src/librustdoc/html/layout.rs | 71 +- src/librustdoc/html/markdown.rs | 10 +- src/librustdoc/html/render.rs | 61 +- .../html/static/jquery-2.1.0.min.js | 4 - .../html/static/jquery-2.1.4.min.js | 4 + src/librustdoc/html/static/main.css | 33 +- src/librustdoc/html/static/main.js | 87 +- src/librustdoc/html/static/playpen.js | 11 +- src/librustdoc/lib.rs | 12 +- src/librustdoc/markdown.rs | 7 +- src/librustdoc/passes.rs | 4 +- src/librustdoc/test.rs | 2 +- src/libserialize/collection_impls.rs | 3 + src/libserialize/hex.rs | 6 +- src/libstd/ascii.rs | 83 +- src/libstd/collections/hash/map.rs | 15 +- src/libstd/collections/hash/set.rs | 6 +- src/libstd/collections/hash/state.rs | 2 +- src/libstd/dynamic_lib.rs | 4 +- src/libstd/env.rs | 17 +- src/libstd/error.rs | 102 +- src/libstd/ffi/c_str.rs | 70 +- src/libstd/fs.rs | 72 +- src/libstd/io/buffered.rs | 410 +- src/libstd/io/cursor.rs | 154 +- src/libstd/io/error.rs | 47 +- src/libstd/io/mod.rs | 967 ++- src/libstd/io/prelude.rs | 4 - src/libstd/io/stdio.rs | 140 +- src/libstd/io/util.rs | 50 +- src/libstd/lib.rs | 211 +- src/libstd/macros.rs | 25 +- src/libstd/net/ip.rs | 14 +- src/libstd/net/mod.rs | 3 +- src/libstd/net/tcp.rs | 25 +- src/libstd/net/udp.rs | 28 +- src/libstd/num/f32.rs | 119 +- src/libstd/num/f64.rs | 16 +- src/libstd/num/i16.rs | 5 +- src/libstd/num/i32.rs | 5 +- src/libstd/num/i64.rs | 5 +- src/libstd/num/i8.rs | 5 +- src/libstd/num/isize.rs | 5 +- src/libstd/num/u16.rs | 5 +- src/libstd/num/u32.rs | 5 +- src/libstd/num/u64.rs | 5 +- src/libstd/num/u8.rs | 5 +- src/libstd/num/uint_macros.rs | 1 - src/libstd/num/usize.rs | 5 +- src/libstd/os/freebsd/raw.rs | 191 +- src/libstd/os/mod.rs | 1 + src/libstd/os/netbsd/mod.rs | 20 + src/libstd/os/netbsd/raw.rs | 71 + src/libstd/path.rs | 5 +- src/libstd/prelude/mod.rs | 107 +- src/libstd/primitive_docs.rs | 421 + src/libstd/process.rs | 35 +- src/libstd/rand/os.rs | 13 +- src/libstd/rt/args.rs | 1 + src/libstd/rt/dwarf/eh.rs | 159 + src/libstd/rt/dwarf/mod.rs | 107 + src/libstd/rt/libunwind.rs | 4 +- src/libstd/rt/macros.rs | 4 +- src/libstd/rt/mod.rs | 8 +- src/libstd/rt/unwind/gcc.rs | 190 +- src/libstd/rt/unwind/mod.rs | 30 +- src/libstd/rt/unwind/seh.rs | 132 +- src/libstd/rt/unwind/seh64_gnu.rs | 227 + src/libstd/rt/util.rs | 25 - src/libstd/rtdeps.rs | 5 +- src/libstd/sync/condvar.rs | 3 +- src/libstd/sync/future.rs | 3 +- src/libstd/sync/mpsc/mod.rs | 46 +- src/libstd/sync/mpsc/select.rs | 6 +- src/libstd/sync/mutex.rs | 3 +- src/libstd/sync/rwlock.rs | 3 +- src/libstd/sync/semaphore.rs | 3 +- src/libstd/sys/common/io.rs | 139 + src/libstd/sys/common/mod.rs | 1 + src/libstd/sys/common/net.rs | 6 + src/libstd/sys/common/stack.rs | 18 +- src/libstd/sys/common/thread_info.rs | 8 +- src/libstd/sys/common/wtf8.rs | 71 +- src/libstd/sys/unix/backtrace.rs | 11 +- src/libstd/sys/unix/c.rs | 10 +- src/libstd/sys/unix/condvar.rs | 4 +- src/libstd/sys/unix/ext/fs.rs | 22 + src/libstd/sys/unix/ext/io.rs | 35 +- src/libstd/sys/unix/ext/mod.rs | 2 +- src/libstd/sys/unix/ext/process.rs | 22 +- src/libstd/sys/unix/fs.rs | 40 +- src/libstd/sys/unix/mod.rs | 1 + src/libstd/sys/unix/net.rs | 14 +- src/libstd/sys/unix/os.rs | 60 +- src/libstd/sys/unix/pipe.rs | 1 + src/libstd/sys/unix/process.rs | 1 + src/libstd/sys/unix/stack_overflow.rs | 2 + src/libstd/sys/unix/sync.rs | 1 + src/libstd/sys/unix/thread.rs | 98 +- src/libstd/sys/unix/thread_local.rs | 2 + src/libstd/sys/unix/time.rs | 1 + src/libstd/sys/windows/c.rs | 290 +- src/libstd/sys/windows/compat.rs | 88 + src/libstd/sys/windows/condvar.rs | 28 +- src/libstd/sys/windows/ext/io.rs | 50 +- src/libstd/sys/windows/ext/process.rs | 28 +- src/libstd/sys/windows/fs.rs | 269 +- src/libstd/sys/windows/mod.rs | 9 +- src/libstd/sys/windows/mutex.rs | 159 +- src/libstd/sys/windows/net.rs | 55 +- src/libstd/sys/windows/os.rs | 5 + src/libstd/sys/windows/pipe.rs | 1 + src/libstd/sys/windows/process.rs | 2 + src/libstd/sys/windows/rwlock.rs | 18 +- src/libstd/sys/windows/stack_overflow.rs | 21 +- src/libstd/sys/windows/stdio.rs | 3 +- src/libstd/sys/windows/sync.rs | 60 - src/libstd/sys/windows/thread.rs | 7 +- src/libstd/sys/windows/thread_local.rs | 11 +- src/libstd/thread/local.rs | 41 +- src/libstd/thread/mod.rs | 89 +- src/libstd/thread/scoped_tls.rs | 34 +- src/libstd/time/duration.rs | 85 +- src/libstd/time/mod.rs | 2 +- src/libstd/tuple.rs | 58 - src/libstd/unit.rs | 45 - src/libsyntax/abi.rs | 2 + src/libsyntax/ast.rs | 58 +- src/libsyntax/ast_util.rs | 4 +- src/libsyntax/attr.rs | 77 +- src/libsyntax/codemap.rs | 198 +- src/libsyntax/diagnostic.rs | 853 +- src/libsyntax/diagnostics/macros.rs | 6 + src/libsyntax/diagnostics/plugin.rs | 25 +- src/libsyntax/ext/base.rs | 6 + src/libsyntax/ext/build.rs | 5 +- src/libsyntax/ext/concat_idents.rs | 4 +- src/libsyntax/ext/deriving/decodable.rs | 16 +- src/libsyntax/ext/deriving/encodable.rs | 8 +- src/libsyntax/ext/deriving/generic/mod.rs | 11 + src/libsyntax/ext/deriving/show.rs | 6 +- src/libsyntax/ext/expand.rs | 229 +- src/libsyntax/ext/format.rs | 6 +- src/libsyntax/ext/pushpop_safe.rs | 94 + src/libsyntax/ext/quote.rs | 4 +- src/libsyntax/ext/source_util.rs | 8 +- src/libsyntax/ext/tt/macro_parser.rs | 14 +- src/libsyntax/ext/tt/macro_rules.rs | 25 +- src/libsyntax/ext/tt/transcribe.rs | 10 +- src/libsyntax/feature_gate.rs | 88 +- src/libsyntax/fold.rs | 3 +- src/libsyntax/lib.rs | 2 + src/libsyntax/parse/lexer/comments.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 63 +- src/libsyntax/parse/mod.rs | 64 +- src/libsyntax/parse/obsolete.rs | 33 - src/libsyntax/parse/parser.rs | 345 +- src/libsyntax/parse/token.rs | 26 +- src/libsyntax/print/pp.rs | 7 +- src/libsyntax/print/pprust.rs | 40 +- src/libsyntax/std_inject.rs | 51 +- src/libsyntax/visit.rs | 7 +- src/libterm/lib.rs | 2 +- src/libterm/terminfo/parm.rs | 4 +- src/libterm/terminfo/parser/compiled.rs | 6 + src/libtest/lib.rs | 33 +- src/rt/arch/aarch64/morestack.S | 6 +- src/rt/msvc/inttypes.h | 305 - src/rt/msvc/stdint.h | 247 - src/rt/msvc/typeof.h | 96 - src/rt/rust_builtin.c | 45 +- src/rt/rust_try.ll | 51 - src/rt/valgrind/memcheck.h | 285 - src/rt/valgrind/valgrind.h | 5414 ------------- src/rust-installer/LICENSE-APACHE | 201 + src/rust-installer/LICENSE-MIT | 25 + src/rust-installer/README.md | 7 + src/rust-installer/install-template.sh | 45 +- src/rustbook/build.rs | 15 +- src/rustbook/javascript.rs | 61 +- src/rustbook/main.rs | 1 - src/rustbook/{css.rs => static/rustbook.css} | 73 +- src/rustbook/static/rustbook.js | 73 + src/rustllvm/ArchiveWrapper.cpp | 179 + src/rustllvm/PassWrapper.cpp | 27 + src/rustllvm/RustWrapper.cpp | 119 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/snapshots.txt | 22 + .../default_ty_param_cross_crate_crate.rs | 19 + .../auxiliary/issue-14344-1.rs} | 6 +- .../auxiliary/issue-14344-2.rs} | 7 +- src/test/auxiliary/issue-25185-1.rs | 18 + src/test/auxiliary/issue-25185-2.rs | 13 + src/test/auxiliary/lang-item-public.rs | 37 +- src/test/auxiliary/lint_group_plugin_test.rs | 10 +- src/test/auxiliary/lint_plugin_test.rs | 4 +- .../lto-syntax-extension-lib.rs} | 6 +- .../auxiliary/lto-syntax-extension-plugin.rs | 21 + src/test/auxiliary/plugin_args.rs | 2 +- src/test/auxiliary/roman_numerals.rs | 4 +- .../rustdoc-impl-parts-crosscrate.rs | 15 + .../auxiliary/stability_attribute_issue.rs | 20 + src/test/bench/core-map.rs | 2 +- src/test/bench/core-set.rs | 2 +- src/test/bench/core-std.rs | 11 +- src/test/bench/msgsend-pipes-shared.rs | 4 +- src/test/bench/msgsend-pipes.rs | 4 +- src/test/bench/msgsend-ring-mutex-arcs.rs | 4 +- src/test/bench/shootout-fasta-redux.rs | 3 +- src/test/bench/shootout-meteor.rs | 3 +- src/test/bench/shootout-pfib.rs | 2 +- src/test/bench/shootout-spectralnorm.rs | 3 +- src/test/bench/std-smallintmap.rs | 8 +- src/test/bench/sudoku.rs | 4 +- src/test/bench/task-perf-alloc-unwind.rs | 2 +- src/test/codegen/link_section.rs | 36 + .../associated-const-impl-wrong-type.rs | 4 +- ...s => associated-item-duplicate-names-2.rs} | 11 +- .../associated-item-duplicate-names-3.rs | 28 + .../associated-item-duplicate-names.rs | 30 + .../associated-types-overridden-default.rs | 26 + src/test/compile-fail/bad-expr-lhs.rs | 10 +- src/test/compile-fail/bad-lint-cap.rs | 14 + src/test/compile-fail/bad-lint-cap2.rs | 17 + src/test/compile-fail/bad-lint-cap3.rs | 20 + .../compile-fail/borrowck-lend-flow-if.rs | 1 + .../compile-fail/borrowck-lend-flow-loop.rs | 1 + src/test/compile-fail/borrowck-lend-flow.rs | 1 + .../borrowck-loan-in-overloaded-op.rs | 1 + src/test/compile-fail/cast-as-bool.rs | 7 +- src/test/compile-fail/cast-rfc0401.rs | 82 +- src/test/compile-fail/cfg-empty-codemap.rs | 18 + .../closure-referencing-itself-issue-25954.rs | 28 + src/test/compile-fail/coherence-orphan.rs | 1 - .../const-cast-different-types.rs | 4 +- src/test/compile-fail/const-eval-overflow.rs | 9 - src/test/compile-fail/const-recursive.rs | 5 +- .../compile-fail/default_ty_param_conflict.rs | 32 + .../default_ty_param_conflict_cross_crate.rs | 29 + src/test/compile-fail/dropck_misc_variants.rs | 47 + src/test/compile-fail/enum-to-float-cast-2.rs | 4 +- src/test/compile-fail/enum-to-float-cast.rs | 4 +- src/test/compile-fail/enum-variant-type-2.rs | 4 +- src/test/compile-fail/fat-ptr-cast.rs | 12 +- .../compile-fail/feature-gate-box-expr.rs | 14 +- .../feature-gate-placement-expr.rs | 28 + .../feature-gate-prelude_import.rs | 14 + .../feature-gate-pushpop-unsafe.rs | 14 + .../compile-fail/generic-extern-lifetime.rs | 25 + .../infinite-tag-type-recursion.rs | 2 +- .../compile-fail/invalid-macro-matcher.rs | 16 + src/test/compile-fail/issue-13407.rs | 2 +- src/test/compile-fail/issue-14084.rs | 5 +- src/test/compile-fail/issue-14309.rs | 2 +- src/test/compile-fail/issue-14845.rs | 4 +- src/test/compile-fail/issue-15094.rs | 4 +- src/test/compile-fail/issue-15919.rs | 21 + src/test/compile-fail/issue-16250.rs | 2 +- src/test/compile-fail/issue-17252.rs | 4 +- src/test/compile-fail/issue-17431-1.rs | 2 +- src/test/compile-fail/issue-17431-2.rs | 4 +- src/test/compile-fail/issue-17431-3.rs | 2 +- src/test/compile-fail/issue-17431-4.rs | 2 +- src/test/compile-fail/issue-17431-5.rs | 2 +- src/test/compile-fail/issue-17431-6.rs | 2 +- src/test/compile-fail/issue-17431-7.rs | 2 +- src/test/compile-fail/issue-17444.rs | 3 +- src/test/compile-fail/issue-17546.rs | 50 + src/test/compile-fail/issue-18119.rs | 22 + src/test/compile-fail/issue-18183.rs | 13 + src/test/compile-fail/issue-19538.rs | 29 + src/test/compile-fail/issue-20162.rs | 17 + src/test/compile-fail/issue-20225.rs | 9 +- src/test/compile-fail/issue-20825.rs | 20 + src/test/compile-fail/issue-21174.rs | 2 +- src/test/compile-fail/issue-21332.rs | 21 + src/test/compile-fail/issue-21554.rs | 4 +- src/test/compile-fail/issue-22312.rs | 27 + src/test/compile-fail/issue-23302.rs | 24 + src/test/compile-fail/issue-23305.rs | 17 + src/test/compile-fail/issue-23595-1.rs | 26 + src/test/compile-fail/issue-23595-2.rs | 20 + src/test/compile-fail/issue-24356.rs | 4 +- src/test/compile-fail/issue-24357.rs | 18 + src/test/compile-fail/issue-25368.rs | 23 + src/test/compile-fail/issue-25901.rs | 23 + src/test/compile-fail/issue-26217.rs | 16 + src/test/compile-fail/issue-26638.rs | 19 + src/test/compile-fail/issue-26812.rs | 12 + .../compile-fail/issue-26948.rs} | 14 +- src/test/compile-fail/issue-27008.rs | 21 + src/test/compile-fail/issue-27033.rs | 22 + src/test/compile-fail/issue-27042.rs | 26 + src/test/compile-fail/issue-2718-a.rs | 2 +- src/test/compile-fail/issue-3008-1.rs | 2 +- src/test/compile-fail/issue-3008-2.rs | 5 +- src/test/compile-fail/issue-3008-3.rs | 2 +- src/test/compile-fail/issue-3779.rs | 2 +- src/test/compile-fail/issue-6702.rs | 2 +- src/test/compile-fail/issue-8640.rs | 20 + .../lifetime-bound-will-change-warning.rs | 10 +- src/test/compile-fail/lint-ctypes-enum.rs | 6 +- src/test/compile-fail/lint-ctypes.rs | 42 +- .../compile-fail/lint-exceeding-bitshifts.rs | 6 +- .../compile-fail/lint-stability-fields.rs | 35 +- src/test/compile-fail/lint-stability.rs | 12 +- src/test/compile-fail/lint-type-limits.rs | 11 - .../lint-unconditional-recursion.rs | 77 + .../compile-fail/lint-unused-mut-variables.rs | 9 + src/test/compile-fail/match-range-fail-2.rs | 23 + src/test/compile-fail/match-range-fail.rs | 6 - src/test/compile-fail/move-fragments-2.rs | 30 +- src/test/compile-fail/move-fragments-3.rs | 12 +- .../compile-fail/moves-based-on-type-tuple.rs | 5 +- src/test/compile-fail/no-send-res-ports.rs | 2 +- .../compile-fail/no_owned_box_lang_item.rs | 27 + .../object-lifetime-default-ambiguous.rs | 5 +- .../object-lifetime-default-elision.rs | 6 +- ...ct-lifetime-default-from-rptr-box-error.rs | 31 + ...lifetime-default-from-rptr-struct-error.rs | 37 + .../object-lifetime-default-mybox.rs | 5 +- .../old-suffixes-are-really-forbidden.rs | 4 +- .../compile-fail/pushpop-unsafe-rejects.rs | 74 + src/test/compile-fail/recursive-enum.rs | 2 +- src/test/compile-fail/ref-suggestion.rs | 33 + src/test/compile-fail/regions-name-static.rs | 2 +- .../regions-proc-bound-capture.rs | 2 +- src/test/compile-fail/regions-static-bound.rs | 24 + src/test/compile-fail/repeat_count.rs | 45 +- .../compile-fail/stability-attribute-issue.rs | 21 + .../stability-attribute-sanity.rs | 1 + .../compile-fail/static-recursion-gate-2.rs | 14 + .../compile-fail/static-recursion-gate.rs | 16 + src/test/compile-fail/str-mut-idx.rs | 23 + ...ait-impl-can-not-have-untraitful-items.rs} | 4 + .../trait-impl-method-mismatch.rs | 4 +- src/test/compile-fail/type-recursive.rs | 2 +- .../typeck-cast-pointer-to-float.rs | 3 +- .../unboxed-closure-feature-gate.rs | 2 +- .../unboxed-closure-sugar-not-used-on-fn.rs | 4 +- src/test/compile-fail/unsafe-trait-impl.rs | 4 +- src/test/compile-fail/unsupported-cast.rs | 2 +- .../compile-fail/vector-cast-weirdness.rs | 2 +- .../compile-fail/warn-foreign-int-types.rs | 6 +- src/test/debuginfo/basic-types-metadata.rs | 23 +- ...gdb-pretty-struct-and-enums-pre-gdb-7-7.rs | 4 - .../generic-enum-with-different-disr-sizes.rs | 92 + src/test/parse-fail/bad-lit-suffixes.rs | 32 +- src/test/parse-fail/byte-literals.rs | 2 +- src/test/parse-fail/byte-string-literals.rs | 2 +- src/test/parse-fail/empty-impl-semicolon.rs | 2 +- .../parse-fail/issue-23620-invalid-escapes.rs | 22 +- .../main.rs => parse-fail/issue-27255.rs} | 7 +- src/test/parse-fail/issue-5806.rs | 1 + src/test/parse-fail/issue-8537.rs | 2 +- src/test/parse-fail/macro-doc-comments-1.rs | 19 + src/test/parse-fail/macro-doc-comments-2.rs | 19 + src/test/parse-fail/multitrait.rs | 2 +- src/test/parse-fail/new-unicode-escapes-3.rs | 2 +- src/test/parse-fail/new-unicode-escapes-4.rs | 6 +- .../parenthesized-box-expr-message.rs | 5 +- src/test/parse-fail/raw-str-delim.rs | 2 +- .../parse-fail/trait-bounds-not-on-impl.rs | 2 +- src/test/pretty/issue-4264.pp | 2 +- .../c-link-to-rust-staticlib/Makefile | 2 - src/test/run-make/execution-engine/Makefile | 6 + src/test/run-make/execution-engine/test.rs | 7 +- .../run-make/extern-fn-reachable/Makefile | 4 +- .../extra-filename-with-temp-outputs/Makefile | 2 +- src/test/run-make/graphviz-flowgraph/Makefile | 2 +- .../run-make/lto-syntax-extension/Makefile | 18 - src/test/run-make/no-duplicate-libs/bar.rs | 1 + src/test/run-make/no-duplicate-libs/foo.rs | 2 + src/test/run-make/save-analysis/foo.rs | 15 + .../run-pass-fulldeps/lto-syntax-extension.rs | 24 + src/test/run-pass/coerce-expect-unsized.rs | 5 + ...param_default_dependent_associated_type.rs | 36 + .../default_ty_param_dependent_defaults.rs | 19 + .../default_ty_param_method_call_test.rs | 24 + src/test/run-pass/default_ty_param_struct.rs | 23 + .../default_ty_param_struct_and_type_alias.rs | 40 + .../run-pass/default_ty_param_trait_impl.rs | 25 + .../default_ty_param_trait_impl_simple.rs | 26 + .../run-pass/default_ty_param_type_alias.rs | 19 + src/test/run-pass/down-with-thread-dtors.rs | 38 + src/test/run-pass/dropck_legal_cycles.rs | 759 ++ src/test/run-pass/dst-coerce-rc.rs | 8 +- src/test/run-pass/extern-pass-empty.rs | 1 + .../run-pass/feature-gate-negate-unsigned.rs | 38 + .../hrtb-type-outlives.rs | 4 - .../infer-from-object-trait-issue-26952.rs | 33 + src/test/run-pass/intrinsic-alignment.rs | 1 + src/test/run-pass/intrinsic-move-val.rs | 87 +- src/test/run-pass/issue-10436.rs | 20 + src/test/run-pass/issue-13902.rs | 22 + src/test/run-pass/issue-14229.rs | 30 + src/test/run-pass/issue-14344.rs | 20 + src/test/run-pass/issue-14382.rs | 24 + src/test/run-pass/issue-14821.rs | 28 + src/test/run-pass/issue-17756.rs | 14 + src/test/run-pass/issue-19404.rs | 47 + src/test/run-pass/issue-20544.rs | 27 + .../issue-2063-resource.rs | 6 +- .../{compile-fail => run-pass}/issue-2063.rs | 21 +- src/test/run-pass/issue-20825.rs | 19 + src/test/run-pass/issue-21140.rs | 15 + src/test/run-pass/issue-2214.rs | 2 +- src/test/run-pass/issue-22375.rs | 13 + src/test/run-pass/issue-23491.rs | 17 + src/test/run-pass/issue-24086.rs | 29 + src/test/run-pass/issue-25185.rs | 21 + src/test/run-pass/issue-25343.rs | 16 + src/test/run-pass/issue-26468.rs | 38 + src/test/run-pass/issue-26484.rs | 20 + src/test/run-pass/issue-26641.rs | 15 + src/test/run-pass/issue-26646.rs | 21 + src/test/run-pass/issue-26655.rs | 34 + src/test/run-pass/issue-26709.rs | 26 + src/test/run-pass/issue-26802.rs | 23 + src/test/run-pass/issue-26805.rs | 15 + src/test/run-pass/issue-26996.rs | 19 + src/test/run-pass/issue-2718.rs | 4 +- src/test/run-pass/issue-27240.rs | 33 + src/test/run-pass/issue-27268.rs | 13 + src/test/run-pass/issue-27281.rs | 26 + .../run-pass/issue-27401-dropflag-reinit.rs | 36 + src/test/run-pass/issue-3563-3.rs | 11 +- src/test/run-pass/lang-item-public.rs | 50 - src/test/run-pass/lint-cap.rs | 18 + src/test/run-pass/macro-doc-comments.rs | 33 + src/test/run-pass/macro-doc-escapes.rs | 25 + src/test/run-pass/new-box-syntax.rs | 12 +- .../object-lifetime-default-from-rptr-box.rs | 4 +- ...bject-lifetime-default-from-rptr-struct.rs | 4 +- .../run-pass/parallel-codegen-closures.rs | 1 + src/test/run-pass/placement-in-syntax.rs | 37 + src/test/run-pass/pushpop-unsafe-okay.rs | 56 + src/test/run-pass/realloc-16687.rs | 3 +- src/test/run-pass/rec-align-u64.rs | 1 + src/test/run-pass/regions-static-bound.rs | 28 + src/test/run-pass/semi-after-macro-ty.rs | 17 + src/test/run-pass/smallest-hello-world.rs | 1 + src/test/run-pass/static-recursive.rs | 47 + src/test/run-pass/sync-send-atomics.rs | 22 + src/test/run-pass/tcp-stress.rs | 3 +- src/test/run-pass/trait-to-str.rs | 2 +- src/test/run-pass/traits-issue-26339.rs | 40 + src/test/run-pass/x86stdcall.rs | 1 + .../xcrate-associated-type-defaults.rs | 18 + src/test/rustdoc/impl-parts-crosscrate.rs | 30 + src/test/rustdoc/impl-parts.rs | 23 + src/test/rustdoc/issue-23812.rs | 46 + 889 files changed, 40166 insertions(+), 25530 deletions(-) create mode 100644 mk/cfg/i686-pc-windows-msvc.mk create mode 100644 mk/cfg/i686-unknown-freebsd.mk create mode 100644 mk/cfg/x86_64-unknown-netbsd.mk create mode 100644 src/doc/nomicon/README.md create mode 100644 src/doc/nomicon/SUMMARY.md create mode 100644 src/doc/nomicon/arc-and-mutex.md create mode 100644 src/doc/nomicon/atomics.md create mode 100644 src/doc/nomicon/borrow-splitting.md create mode 100644 src/doc/nomicon/casts.md create mode 100644 src/doc/nomicon/checked-uninit.md create mode 100644 src/doc/nomicon/coercions.md create mode 100644 src/doc/nomicon/concurrency.md create mode 100644 src/doc/nomicon/constructors.md create mode 100644 src/doc/nomicon/conversions.md create mode 100644 src/doc/nomicon/data.md create mode 100644 src/doc/nomicon/destructors.md create mode 100644 src/doc/nomicon/dot-operator.md create mode 100644 src/doc/nomicon/drop-flags.md create mode 100644 src/doc/nomicon/dropck.md create mode 100644 src/doc/nomicon/exception-safety.md create mode 100644 src/doc/nomicon/exotic-sizes.md create mode 100644 src/doc/nomicon/hrtb.md create mode 100644 src/doc/nomicon/leaking.md create mode 100644 src/doc/nomicon/lifetime-elision.md create mode 100644 src/doc/nomicon/lifetime-mismatch.md create mode 100644 src/doc/nomicon/lifetimes.md create mode 100644 src/doc/nomicon/meet-safe-and-unsafe.md create mode 100644 src/doc/nomicon/obrm.md create mode 100644 src/doc/nomicon/other-reprs.md create mode 100644 src/doc/nomicon/ownership.md create mode 100644 src/doc/nomicon/phantom-data.md create mode 100644 src/doc/nomicon/poisoning.md create mode 100644 src/doc/nomicon/races.md create mode 100644 src/doc/nomicon/references.md create mode 100644 src/doc/nomicon/repr-rust.md create mode 100644 src/doc/nomicon/safe-unsafe-meaning.md create mode 100644 src/doc/nomicon/send-and-sync.md create mode 100644 src/doc/nomicon/subtyping.md create mode 100644 src/doc/nomicon/transmutes.md create mode 100644 src/doc/nomicon/unbounded-lifetimes.md create mode 100644 src/doc/nomicon/unchecked-uninit.md create mode 100644 src/doc/nomicon/uninitialized.md create mode 100644 src/doc/nomicon/unwinding.md create mode 100644 src/doc/nomicon/vec-alloc.md create mode 100644 src/doc/nomicon/vec-dealloc.md create mode 100644 src/doc/nomicon/vec-deref.md create mode 100644 src/doc/nomicon/vec-drain.md create mode 100644 src/doc/nomicon/vec-final.md create mode 100644 src/doc/nomicon/vec-insert-remove.md create mode 100644 src/doc/nomicon/vec-into-iter.md create mode 100644 src/doc/nomicon/vec-layout.md create mode 100644 src/doc/nomicon/vec-push-pop.md create mode 100644 src/doc/nomicon/vec-raw.md create mode 100644 src/doc/nomicon/vec-zsts.md create mode 100644 src/doc/nomicon/vec.md create mode 100644 src/doc/nomicon/working-with-unsafe.md create mode 100644 src/doc/trpl/advanced-linking.md create mode 100644 src/doc/trpl/choosing-your-guarantees.md delete mode 100644 src/doc/trpl/for-loops.md delete mode 100644 src/doc/trpl/link-args.md create mode 100644 src/doc/trpl/loops.md delete mode 100644 src/doc/trpl/while-loops.md delete mode 100644 src/etc/snapshot.pyc create mode 100644 src/liballoc/raw_vec.rs delete mode 100644 src/librustc_back/archive.rs delete mode 100644 src/librustc_back/arm.rs delete mode 100644 src/librustc_back/mips.rs delete mode 100644 src/librustc_back/mipsel.rs create mode 100644 src/librustc_back/target/i686_pc_windows_msvc.rs create mode 100644 src/librustc_back/target/i686_unknown_freebsd.rs create mode 100644 src/librustc_back/target/netbsd_base.rs create mode 100644 src/librustc_back/target/x86_64_unknown_netbsd.rs delete mode 100644 src/librustc_back/x86.rs delete mode 100644 src/librustc_back/x86_64.rs create mode 100644 src/librustc_trans/back/archive.rs create mode 100644 src/librustc_trans/back/msvc/mod.rs create mode 100644 src/librustc_trans/back/msvc/registry.rs delete mode 100644 src/librustdoc/html/static/jquery-2.1.0.min.js create mode 100644 src/librustdoc/html/static/jquery-2.1.4.min.js create mode 100644 src/libstd/os/netbsd/mod.rs create mode 100644 src/libstd/os/netbsd/raw.rs create mode 100644 src/libstd/primitive_docs.rs create mode 100644 src/libstd/rt/dwarf/eh.rs create mode 100644 src/libstd/rt/dwarf/mod.rs create mode 100644 src/libstd/rt/unwind/seh64_gnu.rs create mode 100644 src/libstd/sys/common/io.rs create mode 100644 src/libstd/sys/windows/compat.rs delete mode 100644 src/libstd/sys/windows/sync.rs delete mode 100644 src/libstd/tuple.rs delete mode 100644 src/libstd/unit.rs create mode 100644 src/libsyntax/ext/pushpop_safe.rs delete mode 100644 src/rt/msvc/inttypes.h delete mode 100644 src/rt/msvc/stdint.h delete mode 100644 src/rt/msvc/typeof.h delete mode 100644 src/rt/rust_try.ll delete mode 100644 src/rt/valgrind/memcheck.h delete mode 100644 src/rt/valgrind/valgrind.h create mode 100644 src/rust-installer/LICENSE-APACHE create mode 100644 src/rust-installer/LICENSE-MIT rename src/rustbook/{css.rs => static/rustbook.css} (62%) create mode 100644 src/rustbook/static/rustbook.js create mode 100644 src/rustllvm/ArchiveWrapper.cpp create mode 100644 src/test/auxiliary/default_ty_param_cross_crate_crate.rs rename src/{libstd/array.rs => test/auxiliary/issue-14344-1.rs} (86%) rename src/{libstd/bool.rs => test/auxiliary/issue-14344-2.rs} (71%) create mode 100644 src/test/auxiliary/issue-25185-1.rs create mode 100644 src/test/auxiliary/issue-25185-2.rs rename src/test/{run-make/lto-syntax-extension/lib.rs => auxiliary/lto-syntax-extension-lib.rs} (80%) create mode 100644 src/test/auxiliary/lto-syntax-extension-plugin.rs create mode 100644 src/test/auxiliary/rustdoc-impl-parts-crosscrate.rs create mode 100644 src/test/auxiliary/stability_attribute_issue.rs create mode 100644 src/test/codegen/link_section.rs rename src/test/compile-fail/{feature-gate-negate-unsigned.rs => associated-item-duplicate-names-2.rs} (72%) create mode 100644 src/test/compile-fail/associated-item-duplicate-names-3.rs create mode 100644 src/test/compile-fail/associated-item-duplicate-names.rs create mode 100644 src/test/compile-fail/associated-types-overridden-default.rs create mode 100644 src/test/compile-fail/bad-lint-cap.rs create mode 100644 src/test/compile-fail/bad-lint-cap2.rs create mode 100644 src/test/compile-fail/bad-lint-cap3.rs create mode 100644 src/test/compile-fail/cfg-empty-codemap.rs create mode 100644 src/test/compile-fail/closure-referencing-itself-issue-25954.rs create mode 100644 src/test/compile-fail/default_ty_param_conflict.rs create mode 100644 src/test/compile-fail/default_ty_param_conflict_cross_crate.rs create mode 100644 src/test/compile-fail/dropck_misc_variants.rs create mode 100644 src/test/compile-fail/feature-gate-placement-expr.rs create mode 100644 src/test/compile-fail/feature-gate-prelude_import.rs create mode 100644 src/test/compile-fail/feature-gate-pushpop-unsafe.rs create mode 100644 src/test/compile-fail/generic-extern-lifetime.rs create mode 100644 src/test/compile-fail/invalid-macro-matcher.rs create mode 100644 src/test/compile-fail/issue-15919.rs create mode 100644 src/test/compile-fail/issue-17546.rs create mode 100644 src/test/compile-fail/issue-18119.rs create mode 100644 src/test/compile-fail/issue-18183.rs create mode 100644 src/test/compile-fail/issue-19538.rs create mode 100644 src/test/compile-fail/issue-20162.rs create mode 100644 src/test/compile-fail/issue-20825.rs create mode 100644 src/test/compile-fail/issue-21332.rs create mode 100644 src/test/compile-fail/issue-22312.rs create mode 100644 src/test/compile-fail/issue-23302.rs create mode 100644 src/test/compile-fail/issue-23305.rs create mode 100644 src/test/compile-fail/issue-23595-1.rs create mode 100644 src/test/compile-fail/issue-23595-2.rs create mode 100644 src/test/compile-fail/issue-24357.rs create mode 100644 src/test/compile-fail/issue-25368.rs create mode 100644 src/test/compile-fail/issue-25901.rs create mode 100644 src/test/compile-fail/issue-26217.rs create mode 100644 src/test/compile-fail/issue-26638.rs create mode 100644 src/test/compile-fail/issue-26812.rs rename src/{librustc_back/target_strs.rs => test/compile-fail/issue-26948.rs} (63%) create mode 100644 src/test/compile-fail/issue-27008.rs create mode 100644 src/test/compile-fail/issue-27033.rs create mode 100644 src/test/compile-fail/issue-27042.rs create mode 100644 src/test/compile-fail/issue-8640.rs create mode 100644 src/test/compile-fail/match-range-fail-2.rs create mode 100644 src/test/compile-fail/no_owned_box_lang_item.rs create mode 100644 src/test/compile-fail/object-lifetime-default-from-rptr-box-error.rs create mode 100644 src/test/compile-fail/object-lifetime-default-from-rptr-struct-error.rs create mode 100644 src/test/compile-fail/pushpop-unsafe-rejects.rs create mode 100644 src/test/compile-fail/ref-suggestion.rs create mode 100644 src/test/compile-fail/regions-static-bound.rs create mode 100644 src/test/compile-fail/stability-attribute-issue.rs create mode 100644 src/test/compile-fail/static-recursion-gate-2.rs create mode 100644 src/test/compile-fail/static-recursion-gate.rs create mode 100644 src/test/compile-fail/str-mut-idx.rs rename src/test/compile-fail/{trait-impl-can-not-have-untraitful-methods.rs => trait-impl-can-not-have-untraitful-items.rs} (77%) create mode 100644 src/test/debuginfo/generic-enum-with-different-disr-sizes.rs rename src/test/{run-make/lto-syntax-extension/main.rs => parse-fail/issue-27255.rs} (74%) create mode 100644 src/test/parse-fail/macro-doc-comments-1.rs create mode 100644 src/test/parse-fail/macro-doc-comments-2.rs delete mode 100644 src/test/run-make/lto-syntax-extension/Makefile create mode 100644 src/test/run-pass-fulldeps/lto-syntax-extension.rs create mode 100644 src/test/run-pass/default_ty_param_default_dependent_associated_type.rs create mode 100644 src/test/run-pass/default_ty_param_dependent_defaults.rs create mode 100644 src/test/run-pass/default_ty_param_method_call_test.rs create mode 100644 src/test/run-pass/default_ty_param_struct.rs create mode 100644 src/test/run-pass/default_ty_param_struct_and_type_alias.rs create mode 100644 src/test/run-pass/default_ty_param_trait_impl.rs create mode 100644 src/test/run-pass/default_ty_param_trait_impl_simple.rs create mode 100644 src/test/run-pass/default_ty_param_type_alias.rs create mode 100644 src/test/run-pass/down-with-thread-dtors.rs create mode 100644 src/test/run-pass/dropck_legal_cycles.rs create mode 100644 src/test/run-pass/feature-gate-negate-unsigned.rs rename src/test/{compile-fail => run-pass}/hrtb-type-outlives.rs (82%) create mode 100644 src/test/run-pass/infer-from-object-trait-issue-26952.rs create mode 100644 src/test/run-pass/issue-10436.rs create mode 100644 src/test/run-pass/issue-13902.rs create mode 100644 src/test/run-pass/issue-14229.rs create mode 100644 src/test/run-pass/issue-14344.rs create mode 100644 src/test/run-pass/issue-14382.rs create mode 100644 src/test/run-pass/issue-14821.rs create mode 100644 src/test/run-pass/issue-17756.rs create mode 100644 src/test/run-pass/issue-19404.rs create mode 100644 src/test/run-pass/issue-20544.rs rename src/test/{compile-fail => run-pass}/issue-2063-resource.rs (85%) rename src/test/{compile-fail => run-pass}/issue-2063.rs (56%) create mode 100644 src/test/run-pass/issue-20825.rs create mode 100644 src/test/run-pass/issue-21140.rs create mode 100644 src/test/run-pass/issue-22375.rs create mode 100644 src/test/run-pass/issue-23491.rs create mode 100644 src/test/run-pass/issue-24086.rs create mode 100644 src/test/run-pass/issue-25185.rs create mode 100644 src/test/run-pass/issue-25343.rs create mode 100644 src/test/run-pass/issue-26468.rs create mode 100644 src/test/run-pass/issue-26484.rs create mode 100644 src/test/run-pass/issue-26641.rs create mode 100644 src/test/run-pass/issue-26646.rs create mode 100644 src/test/run-pass/issue-26655.rs create mode 100644 src/test/run-pass/issue-26709.rs create mode 100644 src/test/run-pass/issue-26802.rs create mode 100644 src/test/run-pass/issue-26805.rs create mode 100644 src/test/run-pass/issue-26996.rs create mode 100644 src/test/run-pass/issue-27240.rs create mode 100644 src/test/run-pass/issue-27268.rs create mode 100644 src/test/run-pass/issue-27281.rs create mode 100644 src/test/run-pass/issue-27401-dropflag-reinit.rs delete mode 100644 src/test/run-pass/lang-item-public.rs create mode 100644 src/test/run-pass/lint-cap.rs create mode 100644 src/test/run-pass/macro-doc-comments.rs create mode 100644 src/test/run-pass/macro-doc-escapes.rs create mode 100644 src/test/run-pass/placement-in-syntax.rs create mode 100644 src/test/run-pass/pushpop-unsafe-okay.rs create mode 100644 src/test/run-pass/regions-static-bound.rs create mode 100644 src/test/run-pass/semi-after-macro-ty.rs create mode 100644 src/test/run-pass/static-recursive.rs create mode 100644 src/test/run-pass/sync-send-atomics.rs create mode 100644 src/test/run-pass/traits-issue-26339.rs create mode 100644 src/test/run-pass/xcrate-associated-type-defaults.rs create mode 100644 src/test/rustdoc/impl-parts-crosscrate.rs create mode 100644 src/test/rustdoc/impl-parts.rs create mode 100644 src/test/rustdoc/issue-23812.rs diff --git a/AUTHORS.txt b/AUTHORS.txt index 7e542470c2..310a91b2d1 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -10,6 +10,7 @@ Aaron Turon Aaron Weiss Abhishek Chanda Adam Bozanich +Adam Heins Adam Jacob Adam Roben Adam Szkoda @@ -17,6 +18,7 @@ Adenilson Cavalcanti Adolfo Ochagavía Adrien Brault Adrien Tétar +Agoston Szepessy Ahmed Charles Aidan Cully Aidan Hobson Sayers @@ -44,6 +46,7 @@ Alexei Sholik Alex Gaynor Alexis Beingessner Alex Lyon +Alex Newman Alex Quach Alex Rønne Petersen Alex Stokes @@ -73,15 +76,19 @@ Andrew Foote Andrew Gallant Andrew Hobden Andrew Kensler +Andrew Kuchev <0coming.soon@gmail.com> Andrew Paseltiner Andrew Poelstra Andrew Seidl Andrew Straw Andrew Wagner Andrzej Janik +Andy Caldwell +Andy Grover Angus Lees Anthony Juckel Anton Löfgren +Antti Keränen Aram Visser Arcterus Areski Belaid @@ -93,6 +100,7 @@ Armin Ronacher Arpad Borsos Artem Arthur Liao +arthurprs arturo Ashok Gautham Augusto Hack @@ -134,6 +142,7 @@ Bill Wendling Birunthan Mohanathas Björn Steinbrink blake2-ppc +Blake Loring bluss bluss Boris Egorov @@ -158,6 +167,7 @@ Brian J. Burg Brian Koropoff Brian Leibig Brian Quinlan +Brody Holden Bruno de Oliveira Abinader Bryan Dunsmore Byron Williams @@ -189,7 +199,9 @@ Chris Pressey Chris Sainty Chris Shea Chris Thorn +Christian Persson Christian Stadelmann +Christian Weinz Christoph Burgdorf Christopher Bergqvist Christopher Chambers @@ -228,6 +240,7 @@ Dan Albert Dan Burkert Dan Callahan Dan Connolly +Daniel Albert Daniel Brooks Daniel Fagnan Daniel Farina @@ -278,6 +291,7 @@ Derek Chiang Derek Guenther Derek Harland dgoon +diaphore Diego Giagio Diego Ongaro Diggory Blake @@ -285,6 +299,7 @@ Diggory Hardy Dimitri Krassovski Dirk Gadsden Dirkjan Bussink +Dirkjan Ochtman Dirk Leifeld Div Shekhar diwic @@ -319,6 +334,7 @@ Ehsanul Hoque Elantsev Serj Eli Friedman eliovir +Eljay Elliott Slaughter Elly Fong-Jones elszben @@ -343,6 +359,8 @@ Erik Michaels-Ober Erik Price Erik Rose Erwan +Esption +eternaleye Etienne Millon Eunchong Yu Eunji Jeong @@ -371,6 +389,7 @@ fort Francisco Souza frankamp Franklin Chen +Frank McSherry Franziska Hinkelmann free-Runner FuGangqiang @@ -392,6 +411,7 @@ Geoff Hill Geoffrey Thomas Geoffroy Couprie Geoffry Song +Georg Brandl George Papanikolaou Georges Dubus Germano Gabbianelli @@ -478,6 +498,7 @@ Jan Andersson Jan Bujak Jan-Erik Rediger Jan Kobler +Jan Likar Jan Niklas Hasse Jannis Harder Jannis Redmann @@ -486,6 +507,7 @@ Jarod Liu Jashank Jeremy Jason Fager Jason Orendorff +Jason Schein Jason Thompson Jason Toffaletti Jason Yeo @@ -499,6 +521,7 @@ J.C. Moyer Jeaye Jed Davis Jed Estep +Jeehoon Kang Jeff Balogh Jeff Belgum Jeff Muizelaar @@ -515,6 +538,8 @@ Jesse Luehrs Jesse Ray Jesse Ruderman Jessy Diamond Exum +Jesús Espino +jethrogb Jexell Jihyeok Seo Jihyun Yu @@ -556,6 +581,7 @@ joliv Jonas Hietala Jonathan Bailey Jonathan Boyett +Jonathan Hansford Jonathan Reem Jonathan S Jonathan Sternberg @@ -571,6 +597,7 @@ Jorge Aparicio Jorge Israel Peña Joris Rehm Jormundir +Jose Narvaez Joseph Crail Joseph Martin Joseph Rushton Wakeling @@ -595,6 +622,7 @@ Justin Noah juxiliary jxv Jyun-Yan You +Kagami Sascha Rosylight Kang Seonghoon Kasey Carrothers Keegan McAllister @@ -613,13 +641,17 @@ Kevin Rauwolf Kevin Walter Kevin Yap kgv +Kieran Hunt Kiet Tran Kim Røen kjpgit klutzy KokaKiwi korenchkin +Kornel Lesiński Kostas Karachalios +Kristof Söderström +krumelmonster Krzysztof Drewniak Kubilay Kocak kulakowski @@ -635,6 +667,7 @@ Leah Hanson Lee Aronson Lee Jeffery Lee Wondong +Leif Arne Storset LemmingAvalanche Lennart Kudling Leo Correa @@ -664,6 +697,7 @@ madmalik Magnus Auvinen Mahmut Bulut maikklein +Makoto Kato Makoto Nakashima Manish Goregaokar Manuel Hoffmann @@ -675,6 +709,7 @@ Margaret Meyerhofer Marijn Haverbeke Marin Atanasov Nikolov Mário Feroldi +Mark Buer Mark Lacey <641@rudkx.com> Mark Mossberg Mark Rowe @@ -699,6 +734,7 @@ Matt Brubeck Matt Carberry Matt Coffin Matt Cox +Matt Friedman Matthew Astley Matthew Auld Matthew Iselin @@ -753,6 +789,7 @@ Mickaël Delahaye Mickaël Raybaud-Roig Mickaël Salaün Mick Koch +midinastasurazz Mihnea Dobrescu-Balaur Mike Boutin Mike Dilger @@ -762,6 +799,7 @@ Mike Robinson Mike Sampson Mikhail Zabaluev Mikko Perttunen +mitaa mitchmindtree Mohammed Attia moonglum @@ -795,6 +833,7 @@ Nick Howell Nick Platt Nick Sarten Nicolas Silva +Nicolette Verlinden Niels Egberts Niels langager Ellegaard Nif Ward @@ -814,7 +853,6 @@ Oak OGINO Masanori OlegTsyba Oliver Schneider -Oliver Schneider Olivier Saut olivren Olle Jonsson @@ -849,6 +887,7 @@ Paul Quint Paul Stansifer Paul Woolcock Pavel Panchekha +Pavel Pravosud Pawel Olzacki Pedro Larroy Peer Aramillo Irizar @@ -885,6 +924,7 @@ Q.P.Liu qwitwa Rafael Ávila de Espíndola Rahul Horé +Ralf Jung Ralph Bodenner Ralph Giles Ramkumar Ramachandra @@ -940,6 +980,7 @@ Russell McClellan Ruud van Asseldonk Ryan Levick Ryan Mulligan +Ryan Pendleton Ryan Prichard Ryan Riginding Ryan Scheel @@ -958,7 +999,7 @@ Santiago Rodriguez Saurabh Anand Scott Jenkins Scott Lawrence -Scott Olson +Scott Olson Sean Bowe Sean Chalmers Sean Collins @@ -1024,6 +1065,7 @@ Subhash Bhushan sumito3478 Swaroop C H Sylvestre Ledru +Taliesin Beynon Tamir Duberstein Tamir Duberstein Taras Shpot @@ -1045,6 +1087,7 @@ Thomas Jespersen Thomas Karpiniec Tiago Nobrega Tibor Benke +Ticki Till Hoeppner Tim Brooks Tim Chevalier @@ -1086,7 +1129,7 @@ Tyler Bindon Tyler Thrailkill tynopex Ty Overby -Ulrik Sverdrup +Ulrik Sverdrup Ulysse Carion User Jyyou Utkarsh Kukreti @@ -1102,6 +1145,7 @@ Vijay Korapaty Viktor Dahl ville-h Vincent Belliard +Vincent Bernat Vinzent Steinberg Virgile Andreani visualfc @@ -1109,6 +1153,7 @@ Vitali Haravy Vivek Galatage Vladimir Matveev Vladimir Pouzanov +Vladimir Rutsky Vladimir Smola Vojtech Kral Volker Mische @@ -1125,6 +1170,7 @@ Wilfred Hughes Will Andrews Will Engler Will Hipschman +William Throwe William Ting Willson Mock Will diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0bcb321985..22a23de070 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,6 +83,21 @@ feature. We use the 'fork and pull' model described there. Please make pull requests against the `master` branch. +Compiling all of `make check` can take a while. When testing your pull request, +consider using one of the more specialized `make` targets to cut down on the +amount of time you have to wait. You need to have built the compiler at least +once before running these will work, but that’s only one full build rather than +one each time. + + $ make -j8 rustc-stage1 && make check-stage1 + +is one such example, which builds just `rustc`, and then runs the tests. If +you’re adding something to the standard library, try + + $ make -j8 check-stage1-std NO_REBUILD=1 + +This will not rebuild the compiler, but will run the tests. + 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. @@ -108,14 +123,18 @@ will run all the tests on every platform we support. If it all works out, [merge-queue]: http://buildbot.rust-lang.org/homu/queue/rust +Speaking of tests, Rust has a comprehensive test suite. More information about +it can be found +[here](https://github.com/rust-lang/rust-wiki-backup/blob/master/Note-testsuite.md). + ## Writing Documentation Documentation improvements are very welcome. The source of `doc.rust-lang.org` is located in `src/doc` in the tree, and standard API documentation is generated from the source code itself. -Documentation pull requests function in the same as other pull requests, though -you may see a slightly different form of `r+`: +Documentation pull requests function in the same way as other pull requests, +though you may see a slightly different form of `r+`: @bors: r+ 38fe8d2 rollup diff --git a/Makefile.in b/Makefile.in index d3bb5a541a..8968fabf1b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -62,6 +62,7 @@ # * tidy-basic - show file / line stats # * tidy-errors - show the highest rustc error code # * tidy-features - show the status of language and lib features +# * rustc-stage$(stage) - Only build up to a specific stage # # Then mix in some of these environment variables to harness the # ultimate power of The Rust Build System. @@ -90,7 +91,7 @@ # # # Rust recipes for build system success # -# // Modifying libstd? Use this comment to run unit tests just on your change +# // Modifying libstd? Use this command to run unit tests just on your change # make check-stage1-std NO_REBUILD=1 NO_BENCH=1 # # // Added a run-pass test? Use this to test running your test diff --git a/README.md b/README.md index c8f00ba1ac..9e54704a5e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Rust is a fast systems programming language that guarantees memory safety and offers painless concurrency ([no data races]). It does not employ a garbage collector and has minimal runtime overhead. -This repo contains the code for `rustc`, the Rust compiler, as well +This repo contains the code for the compiler (`rustc`), as well as standard libraries, tools and documentation for Rust. [no data races]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html @@ -73,7 +73,7 @@ Read ["Installing Rust"] from [The Book]. ``` 3. Run `mingw32_shell.bat` or `mingw64_shell.bat` from wherever you installed - MYSY2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust. + MSYS2 (i.e. `C:\msys`), depending on whether you want 32-bit or 64-bit Rust. 4. Navigate to Rust's source code, configure and build it: diff --git a/RELEASES.md b/RELEASES.md index 7cf5e50f7b..7a13cfd61c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,209 @@ +Version 1.3.0 (September 2015) +============================== + +* ~900 changes, numerous bugfixes + +Highlights +---------- + +* The [new object lifetime defaults][nold] have been [turned + on][nold2] after a cycle of warnings about the change. Now types + like `&'a Box` (or `&'a Rc`, etc) will change from + being interpreted as `&'a Box` to `&'a + Box`. +* [The Rustonomicon][nom] is a new book in the official documentation + that dives into writing unsafe Rust. +* The [`Duration`] API, [has been stabilized][ds]. This basic unit of + timekeeping is employed by other std APIs, as well as out-of-tree + time crates. + +Breaking Changes +---------------- + +* The [new object lifetime defaults][nold] have been [turned + on][nold2] after a cycle of warnings about the change. +* There is a known [regression][lr] in how object lifetime elision is + interpreted, the proper solution for which is undetermined. +* The `#[prelude_import]` attribute, an internal implementation + detail, was accidentally stabilized previously. [It has been put + behind the `prelude_import` feature gate][pi]. This change is + believed to break no existing code. +* The behavior of [`size_of_val`][dst1] and [`align_of_val`][dst2] is + [more sane for dynamically sized types][dst3]. Code that relied on + the previous behavior is thought to be broken. +* The `dropck` rules, which checks that destructors can't access + destroyed values, [have been updated][dropck] to match the + [RFC][dropckrfc]. This fixes some soundness holes, and as such will + cause some previously-compiling code to no longer build. + +Language +-------- + +* The [new object lifetime defaults][nold] have been [turned + on][nold2] after a cycle of warnings about the change. +* Semicolons may [now follow types and paths in + macros](https://github.com/rust-lang/rust/pull/27000). +* The behavior of [`size_of_val`][dst1] and [`align_of_val`][dst2] is + [more sane for dynamically sized types][dst3]. Code that relied on + the previous behavior is not known to exist, and suspected to be + broken. +* `'static` variables [may now be recursive][st]. +* `ref` bindings choose between [`Deref`] and [`DerefMut`] + implementations correctly. +* The `dropck` rules, which checks that destructors can't access + destroyed values, [have been updated][dropck] to match the + [RFC][dropckrfc]. + +Libraries +--------- + +* The [`Duration`] API, [has been stabilized][ds], as well as the + `std::time` module, which presently contains only `Duration`. +* `Box` and `Box<[T]>` both implement `Clone`. +* The owned C string, [`CString`], implements [`Borrow`] and the + borrowed C string, [`CStr`], implements [`ToOwned`]. The two of + these allow C strings to be borrowed and cloned in generic code. +* [`CStr`] implements [`Debug`]. +* [`AtomicPtr`] implements [`Debug`]. +* [`Error`] trait objects [can be downcast to their concrete types][e] + in many common configurations, using the [`is`], [`downcast`], + [`downcast_ref`] and [`downcast_mut`] methods, similarly to the + [`Any`] trait. +* Searching for substrings now [employs the two-way algorithm][search] + instead of doing a naive search. This gives major speedups to a + number of methods, including [`contains`][sc], [`find`][sf], + [`rfind`][srf], [`split`][ss]. [`starts_with`][ssw] and + [`ends_with`][sew] are also faster. +* The performance of `PartialEq` for slices is [much faster][ps]. +* The [`Hash`] trait offers the default method, [`hash_slice`], which + is overridden and optimized by the implementations for scalars. +* The [`Hasher`] trait now has a number of specialized `write_*` + methods for primitive types, for efficiency. +* The I/O-specific error type, [`std::io::Error`][ie], gained a set of + methods for accessing the 'inner error', if any: [`get_ref`][iegr], + [`get_mut`][iegm], [`into_inner`][ieii]. As well, the implementation + of [`std::error::Error::cause`][iec] also delegates to the inner + error. +* [`process::Child`][pc] gained the [`id`] method, which returns a + `u32` representing the platform-specific process identifier. +* The [`connect`] method on slices is deprecated, replaced by the new + [`join`] method (note that both of these are on the *unstable* + [`SliceConcatExt`] trait, but through the magic of the prelude are + available to stable code anyway). +* The [`Div`] operator is implemented for [`Wrapping`] types. +* [`DerefMut` is implemented for `String`][dms]. +* Performance of SipHash (the default hasher for `HashMap`) is + [better for long data][sh]. +* [`AtomicPtr`] implements [`Send`]. +* The [`read_to_end`] implementations for [`Stdin`] and [`File`] + are now [specialized to use uninitalized buffers for increased + performance][rte]. +* Lifetime parameters of foreign functions [are now resolved + properly][f]. + +Misc +---- + +* Rust can now, with some coercion, [produce programs that run on + Windows XP][xp], though XP is not considered a supported platform. +* Porting Rust on Windows from the GNU toolchain to MSVC continues + ([1][win1], [2][win2], [3][win3], [4][win4]). It is still not + recommended for use in 1.3, though should be fully-functional + in the [64-bit 1.4 beta][b14]. +* On Fedora-based systems installation will [properly configure the + dynamic linker][fl]. +* The compiler gained many new extended error descriptions, which can + be accessed with the `--explain` flag. +* The `dropck` pass, which checks that destructors can't access + destroyed values, [has been rewritten][dropck]. This fixes some + soundness holes, and as such will cause some previously-compiling + code to no longer build. +* `rustc` now uses [LLVM to write archive files where possible][ar]. + Eventually this will eliminate the compiler's dependency on the ar + utility. +* Rust has [preliminary support for i686 FreeBSD][fb] (it has long + supported FreeBSD on x86_64). +* The [`unused_mut`][lum], [`unconditional_recursion`][lur], + [`improper_ctypes`][lic], and [`negate_unsigned`][lnu] lints are + more strict. +* If landing pads are disabled (with `-Z no-landing-pads`), [`panic!` + will kill the process instead of leaking][nlp]. + +[`Any`]: http://doc.rust-lang.org/nightly/std/any/trait.Any.html +[`AtomicPtr`]: http://doc.rust-lang.org/nightly/std/sync/atomic/struct.AtomicPtr.html +[`Borrow`]: http://doc.rust-lang.org/nightly/std/borrow/trait.Borrow.html +[`CStr`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html +[`CString`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html +[`Debug`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html +[`DerefMut`]: http://doc.rust-lang.org/nightly/std/ops/trait.DerefMut.html +[`Deref`]: http://doc.rust-lang.org/nightly/std/ops/trait.Deref.html +[`Div`]: http://doc.rust-lang.org/nightly/std/ops/trait.Div.html +[`Duration`]: http://doc.rust-lang.org/nightly/std/time/struct.Duration.html +[`Error`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html +[`File`]: http://doc.rust-lang.org/nightly/std/fs/struct.File.html +[`Hash`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html +[`Hasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html +[`Send`]: http://doc.rust-lang.org/nightly/std/marker/trait.Send.html +[`SliceConcatExt`]: http://doc.rust-lang.org/nightly/std/slice/trait.SliceConcatExt.html +[`Stdin`]: http://doc.rust-lang.org/nightly/std/io/struct.Stdin.html +[`ToOwned`]: http://doc.rust-lang.org/nightly/std/borrow/trait.ToOwned.html +[`Wrapping`]: http://doc.rust-lang.org/nightly/std/num/struct.Wrapping.html +[`connect`]: http://doc.rust-lang.org/nightly/std/slice/trait.SliceConcatExt.html#method.connect +[`downcast_mut`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html#method.downcast_mut +[`downcast_ref`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html#method.downcast_ref +[`downcast`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html#method.downcast +[`hash_slice`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html#method.hash_slice +[`id`]: http://doc.rust-lang.org/nightly/std/process/struct.Child.html#method.id +[`is`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html#method.is +[`join`]: http://doc.rust-lang.org/nightly/std/slice/trait.SliceConcatExt.html#method.join +[`read_to_end`]: http://doc.rust-lang.org/nightly/std/io/trait.Read.html#method.read_to_end +[ar]: https://github.com/rust-lang/rust/pull/26926 +[b14]: https://static.rust-lang.org/dist/rust-beta-x86_64-pc-windows-msvc.msi +[dms]: https://github.com/rust-lang/rust/pull/26241 +[dropck]: https://github.com/rust-lang/rust/pull/27261 +[dropckrfc]: https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md +[ds]: https://github.com/rust-lang/rust/pull/26818 +[dst1]: http://doc.rust-lang.org/nightly/std/mem/fn.size_of_val.html +[dst2]: http://doc.rust-lang.org/nightly/std/mem/fn.align_of_val.html +[dst3]: https://github.com/rust-lang/rust/pull/27351 +[e]: https://github.com/rust-lang/rust/pull/24793 +[f]: https://github.com/rust-lang/rust/pull/26588 +[fb]: https://github.com/rust-lang/rust/pull/26959 +[fl]: https://github.com/rust-lang/rust-installer/pull/41 +[hs]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html#method.hash_slice +[ie]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html +[iec]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.cause +[iegm]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.get_mut +[iegr]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.get_ref +[ieii]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.into_inner +[lic]: https://github.com/rust-lang/rust/pull/26583 +[lnu]: https://github.com/rust-lang/rust/pull/27026 +[lr]: https://github.com/rust-lang/rust/issues/27248 +[lum]: https://github.com/rust-lang/rust/pull/26378 +[lur]: https://github.com/rust-lang/rust/pull/26783 +[nlp]: https://github.com/rust-lang/rust/pull/27176 +[nold2]: https://github.com/rust-lang/rust/pull/27045 +[nold]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md +[nom]: http://doc.rust-lang.org/nightly/nomicon/ +[pc]: http://doc.rust-lang.org/nightly/std/process/struct.Child.html +[pi]: https://github.com/rust-lang/rust/pull/26699 +[ps]: https://github.com/rust-lang/rust/pull/26884 +[rte]: https://github.com/rust-lang/rust/pull/26950 +[sc]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.contains +[search]: https://github.com/rust-lang/rust/pull/26327 +[sew]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.ends_with +[sf]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.find +[sh]: https://github.com/rust-lang/rust/pull/27280 +[srf]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rfind +[ss]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split +[ssw]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.starts_with +[st]: https://github.com/rust-lang/rust/pull/26630 +[win1]: https://github.com/rust-lang/rust/pull/26569 +[win2]: https://github.com/rust-lang/rust/pull/26741 +[win3]: https://github.com/rust-lang/rust/pull/26741 +[win4]: https://github.com/rust-lang/rust/pull/27210 +[xp]: https://github.com/rust-lang/rust/pull/26569 + Version 1.2.0 (August 2015) =========================== @@ -164,17 +370,16 @@ Version 1.1.0 (June 2015) Highlights ---------- -* The [`std::fs` module has been expanded][fs-expand] to expand the set of +* The [`std::fs` module has been expanded][fs] to expand the set of functionality exposed: * `DirEntry` now supports optimizations like `file_type` and `metadata` which don't incur a syscall on some platforms. * A `symlink_metadata` function has been added. * The `fs::Metadata` structure now lowers to its OS counterpart, providing access to all underlying information. -* The compiler contains extended explanations of many errors. When it - emits such an error it also suggests using the `--explain` flag to - read the extended explanations, which are also [cataloged on the web - site][err]. +* The compiler now contains extended explanations of many errors. When an error + with an explanation occurs the compiler suggests using the `--explain` flag + to read the explanation. Error explanations are also [available online][err-index]. * Thanks to multiple [improvements][sk] to [type checking][pre], as well as other work, the time to bootstrap the compiler decreased by 32%. @@ -182,11 +387,11 @@ Highlights Libraries --------- -* The `str::split_whitespace` method splits a string on unicode +* The [`str::split_whitespace`] method splits a string on unicode whitespace boundaries. * On both Windows and Unix, new extension traits provide conversion of I/O types to and from the underlying system handles. On Unix, these - traits are [`FrowRawFd`] and [`AsRawFd`], on Windows `FromRawHandle` + traits are [`FromRawFd`] and [`AsRawFd`], on Windows `FromRawHandle` and `AsRawHandle`. These are implemented for `File`, `TcpStream`, `TcpListener`, and `UpdSocket`. Further implementations for `std::process` will be stabilized later. @@ -238,15 +443,14 @@ Misc * [The `drop_with_repr_extern` lint warns about mixing `repr(C)` with `Drop`][drop]. -[`split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace -[`Iterator::cloned`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cloned +[`str::split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace [`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html [`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html [`std::os::unix::symlink`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html [`IntoIterator`]: http://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html [`From`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html [rf]: https://github.com/rust-lang/rust/pull/24491 -[err]: http://doc.rust-lang.org/error-index.html +[err-index]: http://doc.rust-lang.org/error-index.html [sk]: https://github.com/rust-lang/rust/pull/24615 [pre]: https://github.com/rust-lang/rust/pull/25323 [file]: https://github.com/rust-lang/rust/pull/24598 @@ -409,7 +613,6 @@ Misc [sw]: https://github.com/rust-lang/rfcs/blob/master/text/1054-str-words.md [th]: https://github.com/rust-lang/rfcs/blob/master/text/0909-move-thread-local-to-std-thread.md [send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md -[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html [moar-ufcs]: https://github.com/rust-lang/rust/pull/22172 [prim-inherent]: https://github.com/rust-lang/rust/pull/23104 [overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md @@ -419,12 +622,10 @@ Misc [string-pattern]: https://github.com/rust-lang/rust/pull/22466 [oibit-final]: https://github.com/rust-lang/rust/pull/21689 [reflect]: https://github.com/rust-lang/rust/pull/23712 -[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md [conversion]: https://github.com/rust-lang/rfcs/pull/529 [num-traits]: https://github.com/rust-lang/rust/pull/23549 [index-value]: https://github.com/rust-lang/rust/pull/23601 [dropck]: https://github.com/rust-lang/rfcs/pull/769 -[fundamental]: https://github.com/rust-lang/rfcs/pull/1023 [ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee [fn-inherit]: https://github.com/rust-lang/rust/pull/23282 [fn-blanket]: https://github.com/rust-lang/rust/pull/23895 @@ -527,7 +728,6 @@ Version 1.0.0-alpha.2 (February 2015) [osstr]: https://github.com/rust-lang/rust/pull/21488 [osstr-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md [Self]: https://github.com/rust-lang/rust/pull/22158 -[ufcs]: https://github.com/rust-lang/rust/pull/21077 [ufcs-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md [un]: https://github.com/rust-lang/rust/pull/22256 diff --git a/configure b/configure index bfd2798022..2c8d78598b 100755 --- a/configure +++ b/configure @@ -283,7 +283,7 @@ opt_core() { fi done else - if [ ! -z "$META" ] + if [ -n "$META" ] then OP="$OP=<$META>" fi @@ -317,12 +317,23 @@ envopt() { fi # If script or environment provided a value, save it. - if [ ! -z "$VV" ] + if [ -n "$VV" ] then putvar $V fi } +enable_if_not_disabled() { + local OP=$1 + local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') + local ENAB_V="CFG_ENABLE_$UOP" + local EXPLICITLY_DISABLED="CFG_DISABLE_${UOP}_PROVIDED" + eval VV=\$$EXPLICITLY_DISABLED + if [ -z "$VV" ]; then + eval $ENAB_V=1 + fi +} + to_llvm_triple() { case $1 in i686-w64-mingw32) echo i686-pc-windows-gnu ;; @@ -405,6 +416,10 @@ case $CFG_OSTYPE in CFG_OSTYPE=unknown-openbsd ;; + NetBSD) + CFG_OSTYPE=unknown-netbsd + ;; + Darwin) CFG_OSTYPE=apple-darwin ;; @@ -586,7 +601,9 @@ valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" 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 "/opt/ndk_standalone" "Android NDK standalone path" +valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path (deprecated)" +valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" +valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" valopt release-channel "dev" "the name of the release channel to build" valopt musl-root "/usr/local" "MUSL root installation directory" @@ -667,10 +684,12 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then CFG_DISABLE_OPTIMIZE=1 CFG_DISABLE_OPTIMIZE_CXX=1 fi - CFG_ENABLE_DEBUG_ASSERTIONS=1 - CFG_ENABLE_DEBUG_JEMALLOC=1 - CFG_ENABLE_DEBUGINFO=1 - CFG_ENABLE_LLVM_ASSERTIONS=1 + + # Set following variables to 1 unless setting already provided + enable_if_not_disabled debug-assertions + enable_if_not_disabled debug-jemalloc + enable_if_not_disabled debuginfo + enable_if_not_disabled llvm-assertions fi # OK, now write the debugging options @@ -750,7 +769,7 @@ probe CFG_LLDB lldb # On MacOS X, invoking `javac` pops up a dialog if the JDK is not # installed. Since `javac` is only used if `antlr4` is available, # probe for it only in this case. -if [ ! -z "$CFG_ANTLR4" ] +if [ -n "$CFG_ANTLR4" ] then probe CFG_JAVAC javac fi @@ -769,14 +788,14 @@ then fi fi -if [ ! -z "$CFG_GDB" ] +if [ -n "$CFG_GDB" ] then # Store GDB's version CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1) putvar CFG_GDB_VERSION fi -if [ ! -z "$CFG_LLDB" ] +if [ -n "$CFG_LLDB" ] then # Store LLDB's version CFG_LLDB_VERSION=$($CFG_LLDB --version 2>/dev/null | head -1) @@ -802,7 +821,7 @@ step_msg "looking for target specific programs" probe CFG_ADB adb -if [ ! -z "$CFG_PANDOC" ] +if [ -n "$CFG_PANDOC" ] then # Extract "MAJOR MINOR" from Pandoc's version number PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' | @@ -828,7 +847,7 @@ then BIN_SUF=.exe fi -if [ ! -z "$CFG_ENABLE_LOCAL_RUST" ] +if [ -n "$CFG_ENABLE_LOCAL_RUST" ] then system_rustc=$(which rustc) if [ -f ${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF} ] @@ -899,20 +918,32 @@ then fi fi +# If the clang isn't already enabled, check for GCC, and if it is missing, turn +# on clang as a backup. +if [ -z "$CFG_ENABLE_CLANG" ] +then + CFG_GCC_VERSION=$("$CFG_GCC" --version 2>&1) + if [ $? -ne 0 ] + then + step_msg "GCC not installed, will try using Clang" + CFG_ENABLE_CLANG=1 + fi +fi + # Okay, at this point, we have made up our minds about whether we are # going to force CFG_ENABLE_CLANG or not; save the setting if so. -if [ ! -z "$CFG_ENABLE_CLANG" ] +if [ -n "$CFG_ENABLE_CLANG" ] then putvar CFG_ENABLE_CLANG fi # Same with jemalloc. save the setting here. -if [ ! -z "$CFG_DISABLE_JEMALLOC" ] +if [ -n "$CFG_DISABLE_JEMALLOC" ] then putvar CFG_DISABLE_JEMALLOC fi -if [ ! -z "$CFG_LLVM_ROOT" -a -z "$CFG_DISABLE_LLVM_VERSION_CHECK" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ] +if [ -n "$CFG_LLVM_ROOT" -a -z "$CFG_DISABLE_LLVM_VERSION_CHECK" -a -e "$CFG_LLVM_ROOT/bin/llvm-config" ] then step_msg "using custom LLVM at $CFG_LLVM_ROOT" @@ -920,7 +951,7 @@ then LLVM_VERSION=$($LLVM_CONFIG --version) case $LLVM_VERSION in - (3.[5-6]*) + (3.[5-7]*) msg "found ok version of LLVM: $LLVM_VERSION" ;; (*) @@ -941,7 +972,7 @@ fi # CFG_ENABLE_CLANG is set, that indicates that we are opting into # running such safeguards. -if [ ! -z "$CC" ] +if [ -n "$CC" ] then msg "skipping compiler inference steps; using provided CC=$CC" CFG_CC="$CC" @@ -954,7 +985,7 @@ then putvar CFG_USING_CLANG fi else - if [ ! -z "$CFG_ENABLE_CLANG" ] + if [ -n "$CFG_ENABLE_CLANG" ] then if [ -z "$CFG_CLANG" ] then @@ -968,23 +999,21 @@ else fi fi -if [ ! -z "$CFG_ENABLE_CLANG" ] +if [ -n "$CFG_ENABLE_CLANG" ] then case "$CC" in (''|*clang) CFG_CLANG_REPORTED_VERSION=$($CFG_CC --version | grep version) - if [[ $CFG_CLANG_REPORTED_VERSION == *"(based on LLVM "* ]] - then + if echo $CFG_CLANG_REPORTED_VERSION | grep -q "(based on LLVM "; then CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*(based on LLVM \(.*\))/\1/') - elif [[ $CFG_CLANG_REPORTED_VERSION == "Apple LLVM"* ]] - then + elif echo $CFG_CLANG_REPORTED_VERSION | grep -q "Apple LLVM"; then CFG_OSX_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/') else CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/') fi - if [ ! -z "$CFG_OSX_CLANG_VERSION" ] + if [ -n "$CFG_OSX_CLANG_VERSION" ] then case $CFG_OSX_CLANG_VERSION in (7.0*) @@ -1013,17 +1042,14 @@ then esac fi -if [ ! -z "$CFG_ENABLE_CCACHE" ] +if [ -n "$CFG_ENABLE_CCACHE" ] then - if [ -z "$CC" ] + if [ -z "$CFG_CCACHE" ] then - if [ -z "$CFG_CCACHE" ] - then - err "ccache requested but not found" - fi - - CFG_CC="ccache $CFG_CC" + err "ccache requested but not found" fi + + CFG_CC="ccache $CFG_CC" fi if [ -z "$CC" -a -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] @@ -1052,6 +1078,14 @@ for target_file in ${CFG_SRC_DIR}mk/cfg/*.mk; do CFG_SUPPORTED_TARGET="${CFG_SUPPORTED_TARGET} $(basename "$target_file" .mk)" done +# copy build-triples to host-triples so that builds are a subset of hosts +V_TEMP="" +for i in $CFG_BUILD $CFG_HOST; +do + echo "$V_TEMP" | grep -qF $i || V_TEMP="$V_TEMP${V_TEMP:+ }$i" +done +CFG_HOST=$V_TEMP + # copy host-triples to target-triples so that hosts are a subset of targets V_TEMP="" for i in $CFG_HOST $CFG_TARGET; @@ -1078,20 +1112,24 @@ do fi case $i in - arm-linux-androideabi) - - if [ ! -f $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-gcc ] + *android*) + upper_snake_target=$(echo "$i" | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') + eval ndk=\$"CFG_${upper_snake_target}_NDK" + if [ -z "$ndk" ] then - err "NDK $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-gcc not found" - fi - if [ ! -f $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-g++ ] - then - err "NDK $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-g++ not found" - fi - if [ ! -f $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-ar ] - then - err "NDK $CFG_ANDROID_CROSS_PATH/bin/arm-linux-androideabi-ar not found" + ndk=$CFG_ANDROID_CROSS_PATH + eval "CFG_${upper_snake_target}_NDK"=$CFG_ANDROID_CROSS_PATH + warn "generic/default Android NDK option is deprecated (use --$i-ndk option instead)" fi + + # Perform a basic sanity check of the NDK + for android_ndk_tool in "$ndk/bin/$i-gcc" "$ndk/bin/$i-g++" "$ndk/bin/$i-ar" + do + if [ ! -f $android_ndk_tool ] + then + err "NDK tool $android_ndk_tool not found (bad or missing --$i-ndk option?)" + fi + done ;; arm-apple-darwin) @@ -1109,7 +1147,7 @@ do fi ;; - x86_64-*-msvc) + *-msvc) # Currently the build system is not configured to build jemalloc # with MSVC, so we omit this optional dependency. step_msg "targeting MSVC, disabling jemalloc" @@ -1143,28 +1181,56 @@ do # INCLUDE and LIB variables for MSVC so we can set those in the # build system as well. install=$(reg QUERY \ - 'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \ + 'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0' \ -v InstallDir) + if [ -z "$install" ]; then + install=$(reg QUERY \ + 'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \ + -v InstallDir) + fi need_ok "couldn't find visual studio install root" CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//') CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT") CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT") - CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe" - CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe" - CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe" + putvar CFG_MSVC_ROOT + + case $i in + x86_64-*) + bits=x86_64 + msvc_part=amd64 + ;; + i686-*) + bits=i386 + msvc_part= + ;; + *) + err "can only target x86 targets for MSVC" + ;; + esac + bindir="${CFG_MSVC_ROOT}/VC/bin" + if [ -n "$msvc_part" ]; then + bindir="$bindir/$msvc_part" + fi + eval CFG_MSVC_BINDIR_$bits="\"$bindir\"" + eval CFG_MSVC_CL_$bits="\"$bindir/cl.exe\"" + eval CFG_MSVC_LIB_$bits="\"$bindir/lib.exe\"" + eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\"" vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat" - CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%") + include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%") need_ok "failed to learn about MSVC's INCLUDE" - CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%") + lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%") need_ok "failed to learn about MSVC's LIB" - putvar CFG_MSVC_ROOT - putvar CFG_MSVC_CL - putvar CFG_MSVC_LIB - putvar CFG_MSVC_LINK - putvar CFG_MSVC_INCLUDE_PATH - putvar CFG_MSVC_LIB_PATH + eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\"" + eval CFG_MSVC_LIB_PATH_${bits}="\"$lib_path\"" + + putvar CFG_MSVC_BINDIR_${bits} + putvar CFG_MSVC_CL_${bits} + putvar CFG_MSVC_LIB_${bits} + putvar CFG_MSVC_LINK_${bits} + putvar CFG_MSVC_INCLUDE_PATH_${bits} + putvar CFG_MSVC_LIB_PATH_${bits} ;; *) @@ -1172,7 +1238,7 @@ do esac done -if [ ! -z "$CFG_PERF" ] +if [ -n "$CFG_PERF" ] then HAVE_PERF_LOGFD=`$CFG_PERF stat --log-fd 2>&1 | grep 'unknown option'` if [ -z "$HAVE_PERF_LOGFD" ]; @@ -1282,11 +1348,11 @@ then "${CFG_GIT}" submodule init # Disable submodules that we're not using - if [ ! -z "${CFG_LLVM_ROOT}" ]; then + if [ -n "${CFG_LLVM_ROOT}" ]; then msg "git: submodule deinit src/llvm" "${CFG_GIT}" submodule deinit src/llvm fi - if [ ! -z "${CFG_JEMALLOC_ROOT}" ]; then + if [ -n "${CFG_JEMALLOC_ROOT}" ]; then msg "git: submodule deinit src/jemalloc" "${CFG_GIT}" submodule deinit src/jemalloc fi @@ -1333,7 +1399,7 @@ do if [ -z $CFG_LLVM_ROOT ] then LLVM_BUILD_DIR=${CFG_BUILD_DIR}$t/llvm - if [ ! -z "$CFG_DISABLE_OPTIMIZE_LLVM" ] + if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ] then LLVM_DBG_OPTS="--enable-debug-symbols --disable-optimized" # Just use LLVM straight from its build directory to @@ -1389,7 +1455,7 @@ do msg "configuring LLVM for $t with cmake" CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF" - if [ ! -z "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then + if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" else CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" @@ -1403,8 +1469,29 @@ do msg "configuring LLVM with:" msg "$CMAKE_ARGS" + case "$CFG_MSVC_ROOT" in + *14.0*) + generator="Visual Studio 14 2015" + ;; + *12.0*) + generator="Visual Studio 12 2013" + ;; + *) + err "can't determine generator for LLVM cmake" + ;; + esac + case "$t" in + x86_64-*) + generator="$generator Win64" + ;; + i686-*) + ;; + *) + err "can only build LLVM for x86 platforms" + ;; + esac (cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \ - -G "Visual Studio 12 2013 Win64" \ + -G "$generator" \ $CMAKE_ARGS) need_ok "LLVM cmake configure failed" fi @@ -1470,11 +1557,26 @@ do (*) msg "inferring LLVM_CXX/CC from CXX/CC = $CXX/$CC" - LLVM_CXX_32="$CXX" - LLVM_CC_32="$CC" + if [ -n "$CFG_ENABLE_CCACHE" ] + then + if [ -z "$CFG_CCACHE" ] + then + err "ccache requested but not found" + fi + + LLVM_CXX_32="ccache $CXX" + LLVM_CC_32="ccache $CC" + + LLVM_CXX_64="ccache $CXX" + LLVM_CC_64="ccache $CC" + else + LLVM_CXX_32="$CXX" + LLVM_CC_32="$CC" + + LLVM_CXX_64="$CXX" + LLVM_CC_64="$CC" + fi - LLVM_CXX_64="$CXX" - LLVM_CC_64="$CC" ;; esac @@ -1584,25 +1686,26 @@ putvar CFG_HOST putvar CFG_TARGET putvar CFG_LIBDIR_RELATIVE putvar CFG_DISABLE_MANAGE_SUBMODULES -putvar CFG_ANDROID_CROSS_PATH +putvar CFG_AARCH64_LINUX_ANDROID_NDK +putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_MANDIR # Avoid spurious warnings from clang by feeding it original source on # ccache-miss rather than preprocessed input. -if [ ! -z "$CFG_ENABLE_CCACHE" ] && [ ! -z "$CFG_USING_CLANG" ] +if [ -n "$CFG_ENABLE_CCACHE" ] && [ -n "$CFG_USING_CLANG" ] then CFG_CCACHE_CPP2=1 putvar CFG_CCACHE_CPP2 fi -if [ ! -z "$CFG_ENABLE_CCACHE" ] +if [ -n "$CFG_ENABLE_CCACHE" ] then CFG_CCACHE_BASEDIR=${CFG_SRC_DIR} putvar CFG_CCACHE_BASEDIR fi -if [ ! -z $BAD_PANDOC ] +if [ -n $BAD_PANDOC ] then CFG_PANDOC= putvar CFG_PANDOC diff --git a/mk/cfg/aarch64-linux-android.mk b/mk/cfg/aarch64-linux-android.mk index d7a1405c3d..274f73834d 100644 --- a/mk/cfg/aarch64-linux-android.mk +++ b/mk/cfg/aarch64-linux-android.mk @@ -1,9 +1,9 @@ # aarch64-linux-android configuration # CROSS_PREFIX_aarch64-linux-android- -CC_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc -CXX_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-g++ -CPP_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-gcc -E -AR_aarch64-linux-android=$(CFG_ANDROID_CROSS_PATH)/bin/aarch64-linux-android-ar +CC_aarch64-linux-android=$(CFG_AARCH64_LINUX_ANDROID_NDK)/bin/aarch64-linux-android-gcc +CXX_aarch64-linux-android=$(CFG_AARCH64_LINUX_ANDROID_NDK)/bin/aarch64-linux-android-g++ +CPP_aarch64-linux-android=$(CFG_AARCH64_LINUX_ANDROID_NDK)/bin/aarch64-linux-android-gcc -E +AR_aarch64-linux-android=$(CFG_AARCH64_LINUX_ANDROID_NDK)/bin/aarch64-linux-android-ar CFG_LIB_NAME_aarch64-linux-android=lib$(1).so CFG_STATIC_LIB_NAME_aarch64-linux-android=lib$(1).a CFG_LIB_GLOB_aarch64-linux-android=lib$(1)-*.so diff --git a/mk/cfg/arm-linux-androideabi.mk b/mk/cfg/arm-linux-androideabi.mk index fdd38ba75f..c084954f2e 100644 --- a/mk/cfg/arm-linux-androideabi.mk +++ b/mk/cfg/arm-linux-androideabi.mk @@ -1,8 +1,8 @@ # arm-linux-androideabi configuration -CC_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc -CXX_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-g++ -CPP_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-gcc -E -AR_arm-linux-androideabi=$(CFG_ANDROID_CROSS_PATH)/bin/arm-linux-androideabi-ar +CC_arm-linux-androideabi=$(CFG_ARM_LINUX_ANDROIDEABI_NDK)/bin/arm-linux-androideabi-gcc +CXX_arm-linux-androideabi=$(CFG_ARM_LINUX_ANDROIDEABI_NDK)/bin/arm-linux-androideabi-g++ +CPP_arm-linux-androideabi=$(CFG_ARM_LINUX_ANDROIDEABI_NDK)/bin/arm-linux-androideabi-gcc -E +AR_arm-linux-androideabi=$(CFG_ARM_LINUX_ANDROIDEABI_NDK)/bin/arm-linux-androideabi-ar CFG_LIB_NAME_arm-linux-androideabi=lib$(1).so CFG_STATIC_LIB_NAME_arm-linux-androideabi=lib$(1).a CFG_LIB_GLOB_arm-linux-androideabi=lib$(1)-*.so diff --git a/mk/cfg/i686-pc-windows-msvc.mk b/mk/cfg/i686-pc-windows-msvc.mk new file mode 100644 index 0000000000..bb1280688a --- /dev/null +++ b/mk/cfg/i686-pc-windows-msvc.mk @@ -0,0 +1,29 @@ +# i686-pc-windows-msvc configuration +CC_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +LINK_i686-pc-windows-msvc="$(CFG_MSVC_LINK_i386)" -nologo +CXX_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +CPP_i686-pc-windows-msvc="$(CFG_MSVC_CL_i386)" -nologo +AR_i686-pc-windows-msvc="$(CFG_MSVC_LIB_i386)" -nologo +CFG_LIB_NAME_i686-pc-windows-msvc=$(1).dll +CFG_STATIC_LIB_NAME_i686-pc-windows-msvc=$(1).lib +CFG_LIB_GLOB_i686-pc-windows-msvc=$(1)-*.{dll,lib} +CFG_LIB_DSYM_GLOB_i686-pc-windows-msvc=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_i686-pc-windows-msvc := +CFG_GCCISH_CFLAGS_i686-pc-windows-msvc := -MD +CFG_GCCISH_CXXFLAGS_i686-pc-windows-msvc := -MD +CFG_GCCISH_LINK_FLAGS_i686-pc-windows-msvc := +CFG_GCCISH_DEF_FLAG_i686-pc-windows-msvc := +CFG_LLC_FLAGS_i686-pc-windows-msvc := +CFG_INSTALL_NAME_i686-pc-windows-msvc = +CFG_EXE_SUFFIX_i686-pc-windows-msvc := .exe +CFG_WINDOWSY_i686-pc-windows-msvc := 1 +CFG_UNIXY_i686-pc-windows-msvc := +CFG_LDPATH_i686-pc-windows-msvc := +CFG_RUN_i686-pc-windows-msvc=$(2) +CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2)) +CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32 + +# All windows nightiles are currently a GNU triple, so this MSVC triple is not +# bootstrapping from itself. This is relevant during stage0, and other parts of +# the build system take this into account. +BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu diff --git a/mk/cfg/i686-unknown-freebsd.mk b/mk/cfg/i686-unknown-freebsd.mk new file mode 100644 index 0000000000..0ac0ca98a2 --- /dev/null +++ b/mk/cfg/i686-unknown-freebsd.mk @@ -0,0 +1,22 @@ +# i686-unknown-freebsd configuration +CC_i686-unknown-freebsd=$(CC) +CXX_i686-unknown-freebsd=$(CXX) +CPP_i686-unknown-freebsd=$(CPP) +AR_i686-unknown-freebsd=$(AR) +CFG_LIB_NAME_i686-unknown-freebsd=lib$(1).so +CFG_STATIC_LIB_NAME_i686-unknown-freebsd=lib$(1).a +CFG_LIB_GLOB_i686-unknown-freebsd=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_i686-unknown-freebsd=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_i686-unknown-freebsd := -m32 -arch i386 -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_i686-unknown-freebsd := -Wall -Werror -g -fPIC -m32 -arch i386 -I/usr/local/include $(CFLAGS) +CFG_GCCISH_LINK_FLAGS_i686-unknown-freebsd := -m32 -shared -fPIC -g -pthread -lrt +CFG_GCCISH_DEF_FLAG_i686-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_i686-unknown-freebsd := +CFG_INSTALL_NAME_i686-unknown-freebsd = +CFG_EXE_SUFFIX_i686-unknown-freebsd := +CFG_WINDOWSY_i686-unknown-freebsd := +CFG_UNIXY_i686-unknown-freebsd := 1 +CFG_LDPATH_i686-unknown-freebsd := +CFG_RUN_i686-unknown-freebsd=$(2) +CFG_RUN_TARG_i686-unknown-freebsd=$(call CFG_RUN_i686-unknown-freebsd,,$(2)) +CFG_GNU_TRIPLE_i686-unknown-freebsd := i686-unknown-freebsd diff --git a/mk/cfg/x86_64-pc-windows-msvc.mk b/mk/cfg/x86_64-pc-windows-msvc.mk index 69a26c03fb..6f12836f05 100644 --- a/mk/cfg/x86_64-pc-windows-msvc.mk +++ b/mk/cfg/x86_64-pc-windows-msvc.mk @@ -1,9 +1,9 @@ # x86_64-pc-windows-msvc configuration -CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo -CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo -AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo +CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK_x86_64)" -nologo +CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL_x86_64)" -nologo +AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB_x86_64)" -nologo CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib} @@ -23,64 +23,6 @@ CFG_RUN_x86_64-pc-windows-msvc=$(2) CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2)) CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32 -# These two environment variables are scraped by the `./configure` script and -# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and -# for `link.exe` to find standard libraries (the LIB variable). -ifdef CFG_MSVC_INCLUDE_PATH -export INCLUDE := $(CFG_MSVC_INCLUDE_PATH) -endif -ifdef CFG_MSVC_LIB_PATH -export LIB := $(CFG_MSVC_LIB_PATH) -endif - -# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs, -# but it's not the one that we want. As a result we make sure that our detected -# `link.exe` shows up in PATH first. -ifdef CFG_MSVC_LINK -export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH) -endif - -# There are more comments about this available in the target specification for -# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe` -# instead of `lib.exe` for assembling archives, so we need to inject this custom -# dependency here. -NATIVE_TOOL_DEPS_core_T_x86_64-pc-windows-msvc += llvm-ar.exe -INSTALLED_BINS_x86_64-pc-windows-msvc += llvm-ar.exe - -# When working with MSVC on windows, each DLL needs to explicitly declare its -# interface to the outside world through some means. The options for doing so -# include: -# -# 1. A custom attribute on each function itself -# 2. A linker argument saying what to export -# 3. A file which lists all symbols that need to be exported -# -# The Rust compiler takes care (1) for us for all Rust code by annotating all -# public-facing functions with dllexport, but we have a few native dependencies -# which need to cross the DLL boundary. The most important of these dependencies -# is LLVM which is linked into `rustc_llvm.dll` but primarily used from -# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be -# exposed from `rustc_llvm.dll` to be forwarded over the boundary. -# -# Unfortunately, at this time, LLVM does not handle this sort of exportation on -# Windows for us, so we're forced to do it ourselves if we want it (which seems -# like the path of least resistance right now). To do this we generate a `.DEF` -# file [1] which we then custom-pass to the linker when building the rustc_llvm -# crate. This DEF file list all symbols that are exported from -# `src/librustc_llvm/lib.rs` and is generated by a small python script. -# -# Fun times! -# -# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx -RUSTFLAGS_rustc_llvm_T_x86_64-pc-windows-msvc += \ - -C link-args="-DEF:x86_64-pc-windows-msvc/rt/rustc_llvm.def" -CUSTOM_DEPS_rustc_llvm_T_x86_64-pc-windows-msvc += \ - x86_64-pc-windows-msvc/rt/rustc_llvm.def - -x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \ - $(S)src/librustc_llvm/lib.rs - $(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA) - # All windows nightiles are currently a GNU triple, so this MSVC triple is not # bootstrapping from itself. This is relevant during stage0, and other parts of # the build system take this into account. diff --git a/mk/cfg/x86_64-unknown-netbsd.mk b/mk/cfg/x86_64-unknown-netbsd.mk new file mode 100644 index 0000000000..401b0fb7ab --- /dev/null +++ b/mk/cfg/x86_64-unknown-netbsd.mk @@ -0,0 +1,22 @@ +# x86_64-unknown-netbsd configuration +CC_x86_64-unknown-netbsd=$(CC) +CXX_x86_64-unknown-netbsd=$(CXX) +CPP_x86_64-unknown-netbsd=$(CPP) +AR_x86_64-unknown-netbsd=$(AR) +CFG_LIB_NAME_x86_64-unknown-netbsd=lib$(1).so +CFG_STATIC_LIB_NAME_x86_64-unknown-netbsd=lib$(1).a +CFG_LIB_GLOB_x86_64-unknown-netbsd=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_x86_64-unknown-netbsd=$(1)-*.dylib.dSYM +CFG_JEMALLOC_CFLAGS_x86_64-unknown-netbsd := -I/usr/local/include $(CFLAGS) +CFG_GCCISH_CFLAGS_x86_64-unknown-netbsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS) +CFG_GCCISH_LINK_FLAGS_x86_64-unknown-netbsd := -shared -fPIC -g -pthread -lrt +CFG_GCCISH_DEF_FLAG_x86_64-unknown-netbsd := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_x86_64-unknown-netbsd := +CFG_INSTALL_NAME_x86_64-unknown-netbsd = +CFG_EXE_SUFFIX_x86_64-unknown-netbsd := +CFG_WINDOWSY_x86_64-unknown-netbsd := +CFG_UNIXY_x86_64-unknown-netbsd := 1 +CFG_LDPATH_x86_64-unknown-netbsd := +CFG_RUN_x86_64-unknown-netbsd=$(2) +CFG_RUN_TARG_x86_64-unknown-netbsd=$(call CFG_RUN_x86_64-unknown-netbsd,,$(2)) +CFG_GNU_TRIPLE_x86_64-unknown-netbsd := x86_64-unknown-netbsd diff --git a/mk/ctags.mk b/mk/ctags.mk index c7a3406a9e..a116f2aba6 100644 --- a/mk/ctags.mk +++ b/mk/ctags.mk @@ -15,24 +15,11 @@ .PHONY: TAGS.emacs TAGS.vi -# This is using a blacklist approach, probably more durable than a whitelist. -# We exclude: external dependencies (llvm, rt/{msvc,vg}), -# tests (compiletest, test) and a couple of other things (rt/arch, etc) -CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \ - $(patsubst ${CFG_SRC_DIR}src/compiletest,, \ - $(patsubst ${CFG_SRC_DIR}src/test,, \ - $(patsubst ${CFG_SRC_DIR}src/etc,, \ - $(patsubst ${CFG_SRC_DIR}src/rt,, \ - $(patsubst ${CFG_SRC_DIR}src/rt/arch,, \ - $(patsubst ${CFG_SRC_DIR}src/rt/msvc,, \ - $(patsubst ${CFG_SRC_DIR}src/rt/vg,, \ - $(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \ - )))))))) -CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS} -# We could use `--languages=Rust`, but there is value in producing tags for the -# C++ parts of the code base too (at the time of writing, those are .h and .cpp -# files in src/rt, src/rt/sync and src/rustllvm); we mainly just want to -# exclude the external dependencies. +CTAGS_LOCATIONS=$(wildcard ${CFG_SRC_DIR}src/lib*) +CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/librust%,, \ + $(patsubst ${CFG_SRC_DIR}src/lib%test,, \ + $(wildcard ${CFG_SRC_DIR}src/lib*))) ${CFG_SRC_DIR}src/libtest +CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=Rust --recurse ${CTAGS_LOCATIONS} TAGS.emacs: ctags -e -f $@ ${CTAGS_OPTS} diff --git a/mk/docs.mk b/mk/docs.mk index 617c3ddf8d..a8ab6d55d7 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -77,7 +77,7 @@ ERR_IDX_GEN = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE) D := $(S)src/doc -DOC_TARGETS := trpl style error-index +DOC_TARGETS := trpl nomicon style error-index COMPILER_DOC_TARGETS := DOC_L10N_TARGETS := @@ -287,6 +287,13 @@ doc/book/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/trpl/*.md) | doc/ $(Q)rm -rf doc/book $(Q)$(RUSTBOOK) build $(S)src/doc/trpl doc/book +nomicon: doc/nomicon/index.html + +doc/nomicon/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/nomicon/*.md) | doc/ + @$(call E, rustbook: $@) + $(Q)rm -rf doc/nomicon + $(Q)$(RUSTBOOK) build $(S)src/doc/nomicon doc/nomicon + style: doc/style/index.html doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/ diff --git a/mk/main.mk b/mk/main.mk index 8983a63e1d..99b0797e24 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -13,12 +13,12 @@ ###################################################################### # The version number -CFG_RELEASE_NUM=1.2.0 +CFG_RELEASE_NUM=1.3.0 # An optional number to put after the label, e.g. '.2' -> '-beta.2' # NB Make sure it starts with a dot to conform to semver pre-release # versions (section 9) -CFG_PRERELEASE_VERSION=.6 +CFG_PRERELEASE_VERSION=.3 # Append a version-dependent hash to each library, so we can install different # versions in the same place @@ -295,7 +295,6 @@ LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir) LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir) LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir) LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))" -LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS)) LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags) ifeq ($$(findstring freebsd,$(1)),freebsd) # On FreeBSD, it may search wrong headers (that are for pre-installed LLVM), diff --git a/mk/platform.mk b/mk/platform.mk index 8a5e58c46f..60fe22cb32 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -238,3 +238,56 @@ endef $(foreach target,$(CFG_TARGET), \ $(eval $(call CFG_MAKE_TOOLCHAIN,$(target)))) + +# There are more comments about this available in the target specification for +# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe` +# instead of `lib.exe` for assembling archives, so we need to inject this custom +# dependency here. +define ADD_LLVM_AR_TO_MSVC_DEPS +ifeq ($$(findstring msvc,$(1)),msvc) +NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe +INSTALLED_BINS_$(1) += llvm-ar.exe +endif +endef + +$(foreach target,$(CFG_TARGET), \ + $(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target)))) + +# When working with MSVC on windows, each DLL needs to explicitly declare its +# interface to the outside world through some means. The options for doing so +# include: +# +# 1. A custom attribute on each function itself +# 2. A linker argument saying what to export +# 3. A file which lists all symbols that need to be exported +# +# The Rust compiler takes care (1) for us for all Rust code by annotating all +# public-facing functions with dllexport, but we have a few native dependencies +# which need to cross the DLL boundary. The most important of these dependencies +# is LLVM which is linked into `rustc_llvm.dll` but primarily used from +# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be +# exposed from `rustc_llvm.dll` to be forwarded over the boundary. +# +# Unfortunately, at this time, LLVM does not handle this sort of exportation on +# Windows for us, so we're forced to do it ourselves if we want it (which seems +# like the path of least resistance right now). To do this we generate a `.DEF` +# file [1] which we then custom-pass to the linker when building the rustc_llvm +# crate. This DEF file list all symbols that are exported from +# `src/librustc_llvm/lib.rs` and is generated by a small python script. +# +# Fun times! +# +# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx +define ADD_RUSTC_LLVM_DEF_TO_MSVC +ifeq ($$(findstring msvc,$(1)),msvc) +RUSTFLAGS_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def" +CUSTOM_DEPS_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def + +$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs + $$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA) +endif +endef + +$(foreach target,$(CFG_TARGET), \ + $(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target)))) + diff --git a/mk/rt.mk b/mk/rt.mk index 777a2a0fd3..69277e774e 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -53,9 +53,7 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \ NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ rust_android_dummy.c -NATIVE_DEPS_rustrt_native_$(1) := \ - rust_try.ll \ - arch/$$(HOST_$(1))/record_sp.S +NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S @@ -69,14 +67,6 @@ NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S RT_OUTPUT_DIR_$(1) := $(1)/rt -$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \ - $$(LLVM_CONFIG_$$(CFG_BUILD)) - @mkdir -p $$(@D) - @$$(call E, compile: $$@) - $$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \ - -filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \ - -relocation-model=pic -o $$@ $$< - $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS) @mkdir -p $$(@D) @$$(call E, compile: $$@) @@ -90,6 +80,17 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \ @mkdir -p $$(@D) @$$(call E, compile: $$@) $$(Q)$$(call CFG_ASSEMBLE_$(1),$$@,$$<) + +# On MSVC targets the compiler's default include path (e.g. where to find system +# headers) is specified by the INCLUDE environment variable. This may not be set +# so the ./configure script scraped the relevant values and this is the location +# that we put them into cl.exe's environment. +ifeq ($$(findstring msvc,$(1)),msvc) +$$(RT_OUTPUT_DIR_$(1))/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) +$(1)/rustllvm/%.o: \ + export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(1))) +endif endef $(foreach target,$(CFG_TARGET),$(eval $(call NATIVE_LIBRARIES,$(target)))) @@ -104,7 +105,6 @@ define THIRD_PARTY_LIB OBJS_$(2)_$(1) := $$(NATIVE_DEPS_$(2)_$(1):%=$$(RT_OUTPUT_DIR_$(1))/%) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.c=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.cpp=.o) -OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.ll=.o) OBJS_$(2)_$(1) := $$(OBJS_$(2)_$(1):.S=.o) NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2)) $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1)) @@ -237,8 +237,12 @@ COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) ifeq ($$(findstring msvc,$(1)),msvc) COMPRT_CC_$(1) := gcc COMPRT_AR_$(1) := ar +ifeq ($$(findstring i686,$(1)),i686) +COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32 +else COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64 endif +endif $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) @$$(call E, make: compiler-rt) diff --git a/mk/rustllvm.mk b/mk/rustllvm.mk index 50d9937014..6adffda7d1 100644 --- a/mk/rustllvm.mk +++ b/mk/rustllvm.mk @@ -24,7 +24,8 @@ LLVM_EXTRA_INCDIRS_$(1)= $$(call CFG_CC_INCLUDE_$(1),$(S)src/llvm/include) \ endif RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \ - ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp) + ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp \ + ArchiveWrapper.cpp) RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \ $$(call CFG_CC_INCLUDE_$(1),$$(LLVM_INCDIR_$(1))) \ diff --git a/mk/target.mk b/mk/target.mk index 3c274dc4fd..c2de9af39c 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -220,3 +220,38 @@ $(foreach target,$(CFG_TARGET), \ $(foreach crate,$(CRATES), \ $(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \ $(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool)))))) + +# For MSVC targets we need to set up some environment variables for the linker +# to work correctly when building Rust crates. These two variables are: +# +# - LIB tells the linker the default search path for finding system libraries, +# for example kernel32.dll +# - PATH needs to be modified to ensure that MSVC's link.exe is first in the +# path instead of MinGW's /usr/bin/link.exe (entirely unrelated) +# +# The values for these variables are detected by the configure script. +define SETUP_LIB_MSVC_ENV_VARS +ifeq ($$(findstring msvc,$(2)),msvc) +$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ + export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2))) +$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ + export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH) +endif +endef +define SETUP_TOOL_MSVC_ENV_VARS +ifeq ($$(findstring msvc,$(2)),msvc) +$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ + export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2))) +$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \ + export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH) +endif +endef + +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach crate,$(CRATES), \ + $(eval $(call SETUP_LIB_MSVC_ENV_VARS,0,$(target),$(host),$(crate)))))) +$(foreach host,$(CFG_HOST), \ + $(foreach target,$(CFG_TARGET), \ + $(foreach tool,$(TOOLS), \ + $(eval $(call SETUP_TOOL_MSVC_ENV_VARS,0,$(target),$(host),$(tool)))))) diff --git a/mk/tests.mk b/mk/tests.mk index 185cc9b2f4..9341166beb 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -162,7 +162,8 @@ $(foreach doc,$(DOCS), \ $(eval $(call DOCTEST,md-$(doc),$(S)src/doc/$(doc).md))) $(foreach file,$(wildcard $(S)src/doc/trpl/*.md), \ $(eval $(call DOCTEST,$(file:$(S)src/doc/trpl/%.md=trpl-%),$(file)))) - +$(foreach file,$(wildcard $(S)src/doc/nomicon/*.md), \ + $(eval $(call DOCTEST,$(file:$(S)src/doc/nomicon/%.md=nomicon-%),$(file)))) ###################################################################### # Main test targets ###################################################################### diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 92a94d23f0..36c6763910 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -15,7 +15,7 @@ #![feature(libc)] #![feature(path_ext)] #![feature(rustc_private)] -#![feature(slice_extras)] +#![feature(slice_splits)] #![feature(str_char)] #![feature(test)] #![feature(vec_push_all)] @@ -90,9 +90,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH"), optflag("h", "help", "show this message")); - assert!(!args.is_empty()); - let argv0 = args[0].clone(); - let args_ = args.tail(); + let (argv0, args_) = args.split_first().unwrap(); if args[1] == "-h" || args[1] == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); println!("{}", getopts::usage(&message, &groups)); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 5a076b8437..5b62f29b82 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -344,7 +344,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { check_lines, breakpoint_lines } = parse_debugger_commands(testfile, "gdb"); - let mut cmds = commands.connect("\n"); + let mut cmds = commands.join("\n"); // compile test file (it should have 'compile-flags:-g' in the header) let compiler_run_result = compile_test(config, props, testfile); @@ -799,7 +799,7 @@ fn cleanup_debug_info_options(options: &Option) -> Option { split_maybe_args(options).into_iter() .filter(|x| !options_to_remove.contains(x)) .collect::>() - .connect(" "); + .join(" "); Some(new_options) } @@ -1126,16 +1126,10 @@ impl fmt::Display for Status { fn compile_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes { - compile_test_(config, props, testfile, &[]) -} - -fn compile_test_(config: &Config, props: &TestProps, - testfile: &Path, extra_args: &[String]) -> ProcRes { let aux_dir = aux_output_dir_name(config, testfile); // FIXME (#9639): This needs to handle non-utf8 paths - let mut link_args = vec!("-L".to_string(), - aux_dir.to_str().unwrap().to_string()); - link_args.extend(extra_args.iter().cloned()); + let link_args = vec!("-L".to_string(), + aux_dir.to_str().unwrap().to_string()); let args = make_compile_args(config, props, link_args, @@ -1144,7 +1138,7 @@ fn compile_test_(config: &Config, props: &TestProps, } fn document(config: &Config, props: &TestProps, - testfile: &Path, extra_args: &[String]) -> (ProcRes, PathBuf) { + testfile: &Path) -> (ProcRes, PathBuf) { let aux_dir = aux_output_dir_name(config, testfile); let out_dir = output_base_name(config, testfile); let _ = fs::remove_dir_all(&out_dir); @@ -1154,7 +1148,6 @@ fn document(config: &Config, props: &TestProps, "-o".to_string(), out_dir.to_str().unwrap().to_string(), testfile.to_str().unwrap().to_string()]; - args.extend(extra_args.iter().cloned()); args.extend(split_maybe_args(&props.compile_flags)); let args = ProcArgs { prog: config.rustdoc_path.to_str().unwrap().to_string(), @@ -1419,7 +1412,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { // Linux and mac don't require adjusting the library search path if cfg!(unix) { - format!("{} {}", prog, args.connect(" ")) + format!("{} {}", prog, args.join(" ")) } else { // Build the LD_LIBRARY_PATH variable as it would be seen on the command line // for diagnostic purposes @@ -1427,7 +1420,7 @@ fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String { format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path)) } - format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.connect(" ")) + format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" ")) } } @@ -1709,15 +1702,18 @@ fn run_codegen_test(config: &Config, props: &TestProps, testfile: &Path) { } fn charset() -> &'static str { - if cfg!(any(target_os = "bitrig", target_os = "freebsd")) { + // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset + if cfg!(target_os = "bitrig") { "auto" + } else if cfg!(target_os = "freebsd") { + "ISO-8859-1" } else { "UTF-8" } } fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) { - let (proc_res, out_dir) = document(config, props, testfile, &[]); + let (proc_res, out_dir) = document(config, props, testfile); if !proc_res.status.success() { fatal_proc_rec("rustdoc failed!", &proc_res); } diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs index 184d62db45..13d6c029ff 100644 --- a/src/compiletest/util.rs +++ b/src/compiletest/util.rs @@ -21,6 +21,7 @@ const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("ios", "ios"), ("linux", "linux"), ("mingw32", "windows"), + ("netbsd", "netbsd"), ("openbsd", "openbsd"), ("win32", "windows"), ("windows", "windows"), diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index e887ed0cc5..5e99876f5d 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -99,7 +99,7 @@ Second, it makes cost explicit. In general, the only safe way to have a non-exhaustive match would be to panic the thread if nothing is matched, though it could fall through if the type of the `match` expression is `()`. This sort of hidden cost and special casing is against the language's philosophy. It's -easy to ignore certain cases by using the `_` wildcard: +easy to ignore all unspecified cases by using the `_` wildcard: ```rust,ignore match val.do_something() { diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index 0374166405..dc80ec4399 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -1,4 +1,7 @@ -% The (old) Rust Pointer Guide +% The Rust Pointer Guide -This content has moved into -[the Rust Programming Language book](book/pointers.html). +This content has been removed, with no direct replacement. Rust only +has two built-in pointer types now, +[references](book/references-and-borrowing.html) and [raw +pointers](book/raw-pointers.html). Older Rusts had many more pointer +types, they’re gone now. diff --git a/src/doc/index.md b/src/doc/index.md index fba919b711..c1f9ea6b3b 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -20,6 +20,13 @@ series of small examples. [rbe]: http://rustbyexample.com/ +# The Standard Library + +We have [API documentation for the entire standard +library](std/index.html). There's a list of crates on the left with more +specific sections, or you can use the search bar at the top to search for +something if you know its name. + # Community & Getting Help If you need help with something, or just want to talk about Rust with others, @@ -75,13 +82,6 @@ There are questions that are asked quite often, so we've made FAQs for them: * [Project FAQ](complement-project-faq.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) -# The Standard Library - -We have [API documentation for the entire standard -library](std/index.html). There's a list of crates on the left with more -specific sections, or you can use the search bar at the top to search for -something if you know its name. - # The Error Index If you encounter an error while compiling your code you may be able to look it diff --git a/src/doc/nomicon/README.md b/src/doc/nomicon/README.md new file mode 100644 index 0000000000..4554652a17 --- /dev/null +++ b/src/doc/nomicon/README.md @@ -0,0 +1,38 @@ +% The Rustonomicon + +#### The Dark Arts of Advanced and Unsafe Rust Programming + +# NOTE: This is a draft document, and may contain serious errors + +> Instead of the programs I had hoped for, there came only a shuddering blackness +and ineffable loneliness; and I saw at last a fearful truth which no one had +ever dared to breathe before — the unwhisperable secret of secrets — The fact +that this language of stone and stridor is not a sentient perpetuation of Rust +as London is of Old London and Paris of Old Paris, but that it is in fact +quite unsafe, its sprawling body imperfectly embalmed and infested with queer +animate things which have nothing to do with it as it was in compilation. + +This book digs into all the awful details that are necessary to understand in +order to write correct Unsafe Rust programs. Due to the nature of this problem, +it may lead to unleashing untold horrors that shatter your psyche into a billion +infinitesimal fragments of despair. + +Should you wish a long and happy career of writing Rust programs, you should +turn back now and forget you ever saw this book. It is not necessary. However +if you intend to write unsafe code -- or just want to dig into the guts of the +language -- this book contains invaluable information. + +Unlike [The Book][trpl] we will be assuming considerable prior knowledge. In +particular, you should be comfortable with basic systems programming and Rust. +If you don't feel comfortable with these topics, you should consider [reading +The Book][trpl] first. Though we will not be assuming that you have, and will +take care to occasionally give a refresher on the basics where appropriate. You +can skip straight to this book if you want; just know that we won't be +explaining everything from the ground up. + +To be clear, this book goes into deep detail. We're going to dig into +exception-safety, pointer aliasing, memory models, and even some type-theory. +We will also be spending a lot of time talking about the different kinds +of safety and guarantees. + +[trpl]: ../book/ diff --git a/src/doc/nomicon/SUMMARY.md b/src/doc/nomicon/SUMMARY.md new file mode 100644 index 0000000000..7d4ef9c251 --- /dev/null +++ b/src/doc/nomicon/SUMMARY.md @@ -0,0 +1,53 @@ +# Summary + +* [Meet Safe and Unsafe](meet-safe-and-unsafe.md) + * [How Safe and Unsafe Interact](safe-unsafe-meaning.md) + * [Working with Unsafe](working-with-unsafe.md) +* [Data Layout](data.md) + * [repr(Rust)](repr-rust.md) + * [Exotically Sized Types](exotic-sizes.md) + * [Other reprs](other-reprs.md) +* [Ownership](ownership.md) + * [References](references.md) + * [Lifetimes](lifetimes.md) + * [Limits of Lifetimes](lifetime-mismatch.md) + * [Lifetime Elision](lifetime-elision.md) + * [Unbounded Lifetimes](unbounded-lifetimes.md) + * [Higher-Rank Trait Bounds](hrtb.md) + * [Subtyping and Variance](subtyping.md) + * [Drop Check](dropck.md) + * [PhantomData](phantom-data.md) + * [Splitting Borrows](borrow-splitting.md) +* [Type Conversions](conversions.md) + * [Coercions](coercions.md) + * [The Dot Operator](dot-operator.md) + * [Casts](casts.md) + * [Transmutes](transmutes.md) +* [Uninitialized Memory](uninitialized.md) + * [Checked](checked-uninit.md) + * [Drop Flags](drop-flags.md) + * [Unchecked](unchecked-uninit.md) +* [Ownership Based Resource Management](obrm.md) + * [Constructors](constructors.md) + * [Destructors](destructors.md) + * [Leaking](leaking.md) +* [Unwinding](unwinding.md) + * [Exception Safety](exception-safety.md) + * [Poisoning](poisoning.md) +* [Concurrency](concurrency.md) + * [Races](races.md) + * [Send and Sync](send-and-sync.md) + * [Atomics](atomics.md) +* [Implementing Vec](vec.md) + * [Layout](vec-layout.md) + * [Allocating](vec-alloc.md) + * [Push and Pop](vec-push-pop.md) + * [Deallocating](vec-dealloc.md) + * [Deref](vec-deref.md) + * [Insert and Remove](vec-insert-remove.md) + * [IntoIter](vec-into-iter.md) + * [RawVec](vec-raw.md) + * [Drain](vec-drain.md) + * [Handling Zero-Sized Types](vec-zsts.md) + * [Final Code](vec-final.md) +* [Implementing Arc and Mutex](arc-and-mutex.md) diff --git a/src/doc/nomicon/arc-and-mutex.md b/src/doc/nomicon/arc-and-mutex.md new file mode 100644 index 0000000000..fcafe55e40 --- /dev/null +++ b/src/doc/nomicon/arc-and-mutex.md @@ -0,0 +1,7 @@ +% Implementing Arc and Mutex + +Knowing the theory is all fine and good, but the *best* way to understand +something is to use it. To better understand atomics and interior mutability, +we'll be implementing versions of the standard library's Arc and Mutex types. + +TODO: ALL OF THIS OMG diff --git a/src/doc/nomicon/atomics.md b/src/doc/nomicon/atomics.md new file mode 100644 index 0000000000..2d567e39f8 --- /dev/null +++ b/src/doc/nomicon/atomics.md @@ -0,0 +1,255 @@ +% Atomics + +Rust pretty blatantly just inherits C11's memory model for atomics. This is not +due this model being particularly excellent or easy to understand. Indeed, this +model is quite complex and known to have [several flaws][C11-busted]. Rather, it +is a pragmatic concession to the fact that *everyone* is pretty bad at modeling +atomics. At very least, we can benefit from existing tooling and research around +C. + +Trying to fully explain the model in this book is fairly hopeless. It's defined +in terms of madness-inducing causality graphs that require a full book to +properly understand in a practical way. If you want all the nitty-gritty +details, you should check out [C's specification (Section 7.17)][C11-model]. +Still, we'll try to cover the basics and some of the problems Rust developers +face. + +The C11 memory model is fundamentally about trying to bridge the gap between the +semantics we want, the optimizations compilers want, and the inconsistent chaos +our hardware wants. *We* would like to just write programs and have them do +exactly what we said but, you know, fast. Wouldn't that be great? + + + + +# Compiler Reordering + +Compilers fundamentally want to be able to do all sorts of crazy transformations +to reduce data dependencies and eliminate dead code. In particular, they may +radically change the actual order of events, or make events never occur! If we +write something like + +```rust,ignore +x = 1; +y = 3; +x = 2; +``` + +The compiler may conclude that it would be best if your program did + +```rust,ignore +x = 2; +y = 3; +``` + +This has inverted the order of events and completely eliminated one event. +From a single-threaded perspective this is completely unobservable: after all +the statements have executed we are in exactly the same state. But if our +program is multi-threaded, we may have been relying on `x` to actually be +assigned to 1 before `y` was assigned. We would like the compiler to be +able to make these kinds of optimizations, because they can seriously improve +performance. On the other hand, we'd also like to be able to depend on our +program *doing the thing we said*. + + + + +# Hardware Reordering + +On the other hand, even if the compiler totally understood what we wanted and +respected our wishes, our hardware might instead get us in trouble. Trouble +comes from CPUs in the form of memory hierarchies. There is indeed a global +shared memory space somewhere in your hardware, but from the perspective of each +CPU core it is *so very far away* and *so very slow*. Each CPU would rather work +with its local cache of the data and only go through all the anguish of +talking to shared memory only when it doesn't actually have that memory in +cache. + +After all, that's the whole point of the cache, right? If every read from the +cache had to run back to shared memory to double check that it hadn't changed, +what would the point be? The end result is that the hardware doesn't guarantee +that events that occur in the same order on *one* thread, occur in the same +order on *another* thread. To guarantee this, we must issue special instructions +to the CPU telling it to be a bit less smart. + +For instance, say we convince the compiler to emit this logic: + +```text +initial state: x = 0, y = 1 + +THREAD 1 THREAD2 +y = 3; if x == 1 { +x = 1; y *= 2; + } +``` + +Ideally this program has 2 possible final states: + +* `y = 3`: (thread 2 did the check before thread 1 completed) +* `y = 6`: (thread 2 did the check after thread 1 completed) + +However there's a third potential state that the hardware enables: + +* `y = 2`: (thread 2 saw `x = 1`, but not `y = 3`, and then overwrote `y = 3`) + +It's worth noting that different kinds of CPU provide different guarantees. It +is common to separate hardware into two categories: strongly-ordered and weakly- +ordered. Most notably x86/64 provides strong ordering guarantees, while ARM +provides weak ordering guarantees. This has two consequences for concurrent +programming: + +* Asking for stronger guarantees on strongly-ordered hardware may be cheap or + even free because they already provide strong guarantees unconditionally. + Weaker guarantees may only yield performance wins on weakly-ordered hardware. + +* Asking for guarantees that are too weak on strongly-ordered hardware is + more likely to *happen* to work, even though your program is strictly + incorrect. If possible, concurrent algorithms should be tested on + weakly-ordered hardware. + + + + + +# Data Accesses + +The C11 memory model attempts to bridge the gap by allowing us to talk about the +*causality* of our program. Generally, this is by establishing a *happens +before* relationship between parts of the program and the threads that are +running them. This gives the hardware and compiler room to optimize the program +more aggressively where a strict happens-before relationship isn't established, +but forces them to be more careful where one is established. The way we +communicate these relationships are through *data accesses* and *atomic +accesses*. + +Data accesses are the bread-and-butter of the programming world. They are +fundamentally unsynchronized and compilers are free to aggressively optimize +them. In particular, data accesses are free to be reordered by the compiler on +the assumption that the program is single-threaded. The hardware is also free to +propagate the changes made in data accesses to other threads as lazily and +inconsistently as it wants. Mostly critically, data accesses are how data races +happen. Data accesses are very friendly to the hardware and compiler, but as +we've seen they offer *awful* semantics to try to write synchronized code with. +Actually, that's too weak. + +**It is literally impossible to write correct synchronized code using only data +accesses.** + +Atomic accesses are how we tell the hardware and compiler that our program is +multi-threaded. Each atomic access can be marked with an *ordering* that +specifies what kind of relationship it establishes with other accesses. In +practice, this boils down to telling the compiler and hardware certain things +they *can't* do. For the compiler, this largely revolves around re-ordering of +instructions. For the hardware, this largely revolves around how writes are +propagated to other threads. The set of orderings Rust exposes are: + +* Sequentially Consistent (SeqCst) +* Release +* Acquire +* Relaxed + +(Note: We explicitly do not expose the C11 *consume* ordering) + +TODO: negative reasoning vs positive reasoning? TODO: "can't forget to +synchronize" + + + +# Sequentially Consistent + +Sequentially Consistent is the most powerful of all, implying the restrictions +of all other orderings. Intuitively, a sequentially consistent operation +cannot be reordered: all accesses on one thread that happen before and after a +SeqCst access stay before and after it. A data-race-free program that uses +only sequentially consistent atomics and data accesses has the very nice +property that there is a single global execution of the program's instructions +that all threads agree on. This execution is also particularly nice to reason +about: it's just an interleaving of each thread's individual executions. This +does not hold if you start using the weaker atomic orderings. + +The relative developer-friendliness of sequential consistency doesn't come for +free. Even on strongly-ordered platforms sequential consistency involves +emitting memory fences. + +In practice, sequential consistency is rarely necessary for program correctness. +However sequential consistency is definitely the right choice if you're not +confident about the other memory orders. Having your program run a bit slower +than it needs to is certainly better than it running incorrectly! It's also +mechanically trivial to downgrade atomic operations to have a weaker +consistency later on. Just change `SeqCst` to `Relaxed` and you're done! Of +course, proving that this transformation is *correct* is a whole other matter. + + + + +# Acquire-Release + +Acquire and Release are largely intended to be paired. Their names hint at their +use case: they're perfectly suited for acquiring and releasing locks, and +ensuring that critical sections don't overlap. + +Intuitively, an acquire access ensures that every access after it stays after +it. However operations that occur before an acquire are free to be reordered to +occur after it. Similarly, a release access ensures that every access before it +stays before it. However operations that occur after a release are free to be +reordered to occur before it. + +When thread A releases a location in memory and then thread B subsequently +acquires *the same* location in memory, causality is established. Every write +that happened before A's release will be observed by B after its release. +However no causality is established with any other threads. Similarly, no +causality is established if A and B access *different* locations in memory. + +Basic use of release-acquire is therefore simple: you acquire a location of +memory to begin the critical section, and then release that location to end it. +For instance, a simple spinlock might look like: + +```rust +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +fn main() { + let lock = Arc::new(AtomicBool::new(true)); // value answers "am I locked?" + + // ... distribute lock to threads somehow ... + + // Try to acquire the lock by setting it to false + while !lock.compare_and_swap(true, false, Ordering::Acquire) { } + // broke out of the loop, so we successfully acquired the lock! + + // ... scary data accesses ... + + // ok we're done, release the lock + lock.store(true, Ordering::Release); +} +``` + +On strongly-ordered platforms most accesses have release or acquire semantics, +making release and acquire often totally free. This is not the case on +weakly-ordered platforms. + + + + +# Relaxed + +Relaxed accesses are the absolute weakest. They can be freely re-ordered and +provide no happens-before relationship. Still, relaxed operations are still +atomic. That is, they don't count as data accesses and any read-modify-write +operations done to them occur atomically. Relaxed operations are appropriate for +things that you definitely want to happen, but don't particularly otherwise care +about. For instance, incrementing a counter can be safely done by multiple +threads using a relaxed `fetch_add` if you're not using the counter to +synchronize any other accesses. + +There's rarely a benefit in making an operation relaxed on strongly-ordered +platforms, since they usually provide release-acquire semantics anyway. However +relaxed operations can be cheaper on weakly-ordered platforms. + + + + + +[C11-busted]: http://plv.mpi-sws.org/c11comp/popl15.pdf +[C11-model]: http://www.open-std.org/jtc1/sc22/wg14/www/standards.html#9899 diff --git a/src/doc/nomicon/borrow-splitting.md b/src/doc/nomicon/borrow-splitting.md new file mode 100644 index 0000000000..cc5bc8a602 --- /dev/null +++ b/src/doc/nomicon/borrow-splitting.md @@ -0,0 +1,291 @@ +% Splitting Borrows + +The mutual exclusion property of mutable references can be very limiting when +working with a composite structure. The borrow checker understands some basic +stuff, but will fall over pretty easily. It does understand structs +sufficiently to know that it's possible to borrow disjoint fields of a struct +simultaneously. So this works today: + +```rust +struct Foo { + a: i32, + b: i32, + c: i32, +} + +let mut x = Foo {a: 0, b: 0, c: 0}; +let a = &mut x.a; +let b = &mut x.b; +let c = &x.c; +*b += 1; +let c2 = &x.c; +*a += 10; +println!("{} {} {} {}", a, b, c, c2); +``` + +However borrowck doesn't understand arrays or slices in any way, so this doesn't +work: + +```rust,ignore +let mut x = [1, 2, 3]; +let a = &mut x[0]; +let b = &mut x[1]; +println!("{} {}", a, b); +``` + +```text +:4:14: 4:18 error: cannot borrow `x[..]` as mutable more than once at a time +:4 let b = &mut x[1]; + ^~~~ +:3:14: 3:18 note: previous borrow of `x[..]` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x[..]` until the borrow ends +:3 let a = &mut x[0]; + ^~~~ +:6:2: 6:2 note: previous borrow ends here +:1 fn main() { +:2 let mut x = [1, 2, 3]; +:3 let a = &mut x[0]; +:4 let b = &mut x[1]; +:5 println!("{} {}", a, b); +:6 } + ^ +error: aborting due to 2 previous errors +``` + +While it was plausible that borrowck could understand this simple case, it's +pretty clearly hopeless for borrowck to understand disjointness in general +container types like a tree, especially if distinct keys actually *do* map +to the same value. + +In order to "teach" borrowck that what we're doing is ok, we need to drop down +to unsafe code. For instance, mutable slices expose a `split_at_mut` function +that consumes the slice and returns two mutable slices. One for everything to +the left of the index, and one for everything to the right. Intuitively we know +this is safe because the slices don't overlap, and therefore alias. However +the implementation requires some unsafety: + +```rust,ignore +fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + assert!(mid <= len); + unsafe { + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } +} +``` + +This is actually a bit subtle. So as to avoid ever making two `&mut`'s to the +same value, we explicitly construct brand-new slices through raw pointers. + +However more subtle is how iterators that yield mutable references work. +The iterator trait is defined as follows: + +```rust +trait Iterator { + type Item; + + fn next(&mut self) -> Option; +} +``` + +Given this definition, Self::Item has *no* connection to `self`. This means that +we can call `next` several times in a row, and hold onto all the results +*concurrently*. This is perfectly fine for by-value iterators, which have +exactly these semantics. It's also actually fine for shared references, as they +admit arbitrarily many references to the same thing (although the iterator needs +to be a separate object from the thing being shared). + +But mutable references make this a mess. At first glance, they might seem +completely incompatible with this API, as it would produce multiple mutable +references to the same object! + +However it actually *does* work, exactly because iterators are one-shot objects. +Everything an IterMut yields will be yielded at most once, so we don't +actually ever yield multiple mutable references to the same piece of data. + +Perhaps surprisingly, mutable iterators don't require unsafe code to be +implemented for many types! + +For instance here's a singly linked list: + +```rust +# fn main() {} +type Link = Option>>; + +struct Node { + elem: T, + next: Link, +} + +pub struct LinkedList { + head: Link, +} + +pub struct IterMut<'a, T: 'a>(Option<&'a mut Node>); + +impl LinkedList { + fn iter_mut(&mut self) -> IterMut { + IterMut(self.head.as_mut().map(|node| &mut **node)) + } +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + self.0.take().map(|node| { + self.0 = node.next.as_mut().map(|node| &mut **node); + &mut node.elem + }) + } +} +``` + +Here's a mutable slice: + +```rust +# fn main() {} +use std::mem; + +pub struct IterMut<'a, T: 'a>(&'a mut[T]); + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + let slice = mem::replace(&mut self.0, &mut []); + if slice.is_empty() { return None; } + + let (l, r) = slice.split_at_mut(1); + self.0 = r; + l.get_mut(0) + } +} + +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option { + let slice = mem::replace(&mut self.0, &mut []); + if slice.is_empty() { return None; } + + let new_len = slice.len() - 1; + let (l, r) = slice.split_at_mut(new_len); + self.0 = l; + r.get_mut(0) + } +} +``` + +And here's a binary tree: + +```rust +# fn main() {} +use std::collections::VecDeque; + +type Link = Option>>; + +struct Node { + elem: T, + left: Link, + right: Link, +} + +pub struct Tree { + root: Link, +} + +struct NodeIterMut<'a, T: 'a> { + elem: Option<&'a mut T>, + left: Option<&'a mut Node>, + right: Option<&'a mut Node>, +} + +enum State<'a, T: 'a> { + Elem(&'a mut T), + Node(&'a mut Node), +} + +pub struct IterMut<'a, T: 'a>(VecDeque>); + +impl Tree { + pub fn iter_mut(&mut self) -> IterMut { + let mut deque = VecDeque::new(); + self.root.as_mut().map(|root| deque.push_front(root.iter_mut())); + IterMut(deque) + } +} + +impl Node { + pub fn iter_mut(&mut self) -> NodeIterMut { + NodeIterMut { + elem: Some(&mut self.elem), + left: self.left.as_mut().map(|node| &mut **node), + right: self.right.as_mut().map(|node| &mut **node), + } + } +} + + +impl<'a, T> Iterator for NodeIterMut<'a, T> { + type Item = State<'a, T>; + + fn next(&mut self) -> Option { + match self.left.take() { + Some(node) => Some(State::Node(node)), + None => match self.elem.take() { + Some(elem) => Some(State::Elem(elem)), + None => match self.right.take() { + Some(node) => Some(State::Node(node)), + None => None, + } + } + } + } +} + +impl<'a, T> DoubleEndedIterator for NodeIterMut<'a, T> { + fn next_back(&mut self) -> Option { + match self.right.take() { + Some(node) => Some(State::Node(node)), + None => match self.elem.take() { + Some(elem) => Some(State::Elem(elem)), + None => match self.left.take() { + Some(node) => Some(State::Node(node)), + None => None, + } + } + } + } +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + fn next(&mut self) -> Option { + loop { + match self.0.front_mut().and_then(|node_it| node_it.next()) { + Some(State::Elem(elem)) => return Some(elem), + Some(State::Node(node)) => self.0.push_front(node.iter_mut()), + None => if let None = self.0.pop_front() { return None }, + } + } + } +} + +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + fn next_back(&mut self) -> Option { + loop { + match self.0.back_mut().and_then(|node_it| node_it.next_back()) { + Some(State::Elem(elem)) => return Some(elem), + Some(State::Node(node)) => self.0.push_back(node.iter_mut()), + None => if let None = self.0.pop_back() { return None }, + } + } + } +} +``` + +All of these are completely safe and work on stable Rust! This ultimately +falls out of the simple struct case we saw before: Rust understands that you +can safely split a mutable reference into subfields. We can then encode +permanently consuming a reference via Options (or in the case of slices, +replacing with an empty slice). diff --git a/src/doc/nomicon/casts.md b/src/doc/nomicon/casts.md new file mode 100644 index 0000000000..5f07709cf4 --- /dev/null +++ b/src/doc/nomicon/casts.md @@ -0,0 +1,71 @@ +% Casts + +Casts are a superset of coercions: every coercion can be explicitly +invoked via a cast. However some conversions require a cast. +While coercions are pervasive and largely harmless, these "true casts" +are rare and potentially dangerous. As such, casts must be explicitly invoked +using the `as` keyword: `expr as Type`. + +True casts generally revolve around raw pointers and the primitive numeric +types. Even though they're dangerous, these casts are infallible at runtime. +If a cast triggers some subtle corner case no indication will be given that +this occurred. The cast will simply succeed. That said, casts must be valid +at the type level, or else they will be prevented statically. For instance, +`7u8 as bool` will not compile. + +That said, casts aren't `unsafe` because they generally can't violate memory +safety *on their own*. For instance, converting an integer to a raw pointer can +very easily lead to terrible things. However the act of creating the pointer +itself is safe, because actually using a raw pointer is already marked as +`unsafe`. + +Here's an exhaustive list of all the true casts. For brevity, we will use `*` +to denote either a `*const` or `*mut`, and `integer` to denote any integral +primitive: + + * `*T as *U` where `T, U: Sized` + * `*T as *U` TODO: explain unsized situation + * `*T as integer` + * `integer as *T` + * `number as number` + * `C-like-enum as integer` + * `bool as integer` + * `char as integer` + * `u8 as char` + * `&[T; n] as *const T` + * `fn as *T` where `T: Sized` + * `fn as integer` + +Note that lengths are not adjusted when casting raw slices - +`*const [u16] as *const [u8]` creates a slice that only includes +half of the original memory. + +Casting is not transitive, that is, even if `e as U1 as U2` is a valid +expression, `e as U2` is not necessarily so. + +For numeric casts, there are quite a few cases to consider: + +* casting between two integers of the same size (e.g. i32 -> u32) is a no-op +* casting from a larger integer to a smaller integer (e.g. u32 -> u8) will + truncate +* casting from a smaller integer to a larger integer (e.g. u8 -> u32) will + * zero-extend if the source is unsigned + * sign-extend if the source is signed +* casting from a float to an integer will round the float towards zero + * **[NOTE: currently this will cause Undefined Behaviour if the rounded + value cannot be represented by the target integer type][float-int]**. + This includes Inf and NaN. This is a bug and will be fixed. +* casting from an integer to float will produce the floating point + representation of the integer, rounded if necessary (rounding strategy + unspecified) +* casting from an f32 to an f64 is perfect and lossless +* casting from an f64 to an f32 will produce the closest possible value + (rounding strategy unspecified) + * **[NOTE: currently this will cause Undefined Behaviour if the value + is finite but larger or smaller than the largest or smallest finite + value representable by f32][float-float]**. This is a bug and will + be fixed. + + +[float-int]: https://github.com/rust-lang/rust/issues/10184 +[float-float]: https://github.com/rust-lang/rust/issues/15536 diff --git a/src/doc/nomicon/checked-uninit.md b/src/doc/nomicon/checked-uninit.md new file mode 100644 index 0000000000..f7c4482a4a --- /dev/null +++ b/src/doc/nomicon/checked-uninit.md @@ -0,0 +1,117 @@ +% Checked Uninitialized Memory + +Like C, all stack variables in Rust are uninitialized until a value is +explicitly assigned to them. Unlike C, Rust statically prevents you from ever +reading them until you do: + +```rust,ignore +fn main() { + let x: i32; + println!("{}", x); +} +``` + +```text +src/main.rs:3:20: 3:21 error: use of possibly uninitialized variable: `x` +src/main.rs:3 println!("{}", x); + ^ +``` + +This is based off of a basic branch analysis: every branch must assign a value +to `x` before it is first used. Interestingly, Rust doesn't require the variable +to be mutable to perform a delayed initialization if every branch assigns +exactly once. However the analysis does not take advantage of constant analysis +or anything like that. So this compiles: + +```rust +fn main() { + let x: i32; + + if true { + x = 1; + } else { + x = 2; + } + + println!("{}", x); +} +``` + +but this doesn't: + +```rust,ignore +fn main() { + let x: i32; + if true { + x = 1; + } + println!("{}", x); +} +``` + +```text +src/main.rs:6:17: 6:18 error: use of possibly uninitialized variable: `x` +src/main.rs:6 println!("{}", x); +``` + +while this does: + +```rust +fn main() { + let x: i32; + if true { + x = 1; + println!("{}", x); + } + // Don't care that there are branches where it's not initialized + // since we don't use the value in those branches +} +``` + +Of course, while the analysis doesn't consider actual values, it does +have a relatively sophisticated understanding of dependencies and control +flow. For instance, this works: + +```rust +let x: i32; + +loop { + // Rust doesn't understand that this branch will be taken unconditionally, + // because it relies on actual values. + if true { + // But it does understand that it will only be taken once because + // we unconditionally break out of it. Therefore `x` doesn't + // need to be marked as mutable. + x = 0; + break; + } +} +// It also knows that it's impossible to get here without reaching the break. +// And therefore that `x` must be initialized here! +println!("{}", x); +``` + +If a value is moved out of a variable, that variable becomes logically +uninitialized if the type of the value isn't Copy. That is: + +```rust +fn main() { + let x = 0; + let y = Box::new(0); + let z1 = x; // x is still valid because i32 is Copy + let z2 = y; // y is now logically uninitialized because Box isn't Copy +} +``` + +However reassigning `y` in this example *would* require `y` to be marked as +mutable, as a Safe Rust program could observe that the value of `y` changed: + +```rust +fn main() { + let mut y = Box::new(0); + let z = y; // y is now logically uninitialized because Box isn't Copy + y = Box::new(1); // reinitialize y +} +``` + +Otherwise it's like `y` is a brand new variable. diff --git a/src/doc/nomicon/coercions.md b/src/doc/nomicon/coercions.md new file mode 100644 index 0000000000..2e33a6729d --- /dev/null +++ b/src/doc/nomicon/coercions.md @@ -0,0 +1,70 @@ +% Coercions + +Types can implicitly be coerced to change in certain contexts. These changes are +generally just *weakening* of types, largely focused around pointers and +lifetimes. They mostly exist to make Rust "just work" in more cases, and are +largely harmless. + +Here's all the kinds of coercion: + +Coercion is allowed between the following types: + +* Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to + `T_3` +* Pointer Weakening: + * `&mut T` to `&T` + * `*mut T` to `*const T` + * `&T` to `*const T` + * `&mut T` to `*mut T` +* Unsizing: `T` to `U` if `T` implements `CoerceUnsized` + +`CoerceUnsized> for Pointer where T: Unsize` is implemented +for all pointer types (including smart pointers like Box and Rc). Unsize is +only implemented automatically, and enables the following transformations: + +* `[T, ..n]` => `[T]` +* `T` => `Trait` where `T: Trait` +* `Foo<..., T, ...>` => `Foo<..., U, ...>` where: + * `T: Unsize` + * `Foo` is a struct + * Only the last field of `Foo` has type `T` + * `T` is not part of the type of any other fields + +Coercions occur at a *coercion site*. Any location that is explicitly typed +will cause a coercion to its type. If inference is necessary, the coercion will +not be performed. Exhaustively, the coercion sites for an expression `e` to +type `U` are: + +* let statements, statics, and consts: `let x: U = e` +* Arguments to functions: `takes_a_U(e)` +* Any expression that will be returned: `fn foo() -> U { e }` +* Struct literals: `Foo { some_u: e }` +* Array literals: `let x: [U; 10] = [e, ..]` +* Tuple literals: `let x: (U, ..) = (e, ..)` +* The last expression in a block: `let x: U = { ..; e }` + +Note that we do not perform coercions when matching traits (except for +receivers, see below). If there is an impl for some type `U` and `T` coerces to +`U`, that does not constitute an implementation for `T`. For example, the +following will not type check, even though it is OK to coerce `t` to `&T` and +there is an impl for `&T`: + +```rust,ignore +trait Trait {} + +fn foo(t: X) {} + +impl<'a> Trait for &'a i32 {} + + +fn main() { + let t: &mut i32 = &mut 0; + foo(t); +} +``` + +```text +:10:5: 10:8 error: the trait `Trait` is not implemented for the type `&mut i32` [E0277] +:10 foo(t); + ^~~ +``` diff --git a/src/doc/nomicon/concurrency.md b/src/doc/nomicon/concurrency.md new file mode 100644 index 0000000000..9dcbecdd5b --- /dev/null +++ b/src/doc/nomicon/concurrency.md @@ -0,0 +1,13 @@ +% Concurrency and Paralellism + +Rust as a language doesn't *really* have an opinion on how to do concurrency or +parallelism. The standard library exposes OS threads and blocking sys-calls +because everyone has those, and they're uniform enough that you can provide +an abstraction over them in a relatively uncontroversial way. Message passing, +green threads, and async APIs are all diverse enough that any abstraction over +them tends to involve trade-offs that we weren't willing to commit to for 1.0. + +However the way Rust models concurrency makes it relatively easy design your own +concurrency paradigm as a library and have everyone else's code Just Work +with yours. Just require the right lifetimes and Send and Sync where appropriate +and you're off to the races. Or rather, off to the... not... having... races. diff --git a/src/doc/nomicon/constructors.md b/src/doc/nomicon/constructors.md new file mode 100644 index 0000000000..97817cd1f9 --- /dev/null +++ b/src/doc/nomicon/constructors.md @@ -0,0 +1,59 @@ +% Constructors + +There is exactly one way to create an instance of a user-defined type: name it, +and initialize all its fields at once: + +```rust +struct Foo { + a: u8, + b: u32, + c: bool, +} + +enum Bar { + X(u32), + Y(bool), +} + +struct Unit; + +let foo = Foo { a: 0, b: 1, c: false }; +let bar = Bar::X(0); +let empty = Unit; +``` + +That's it. Every other way you make an instance of a type is just calling a +totally vanilla function that does some stuff and eventually bottoms out to The +One True Constructor. + +Unlike C++, Rust does not come with a slew of built-in kinds of constructor. +There are no Copy, Default, Assignment, Move, or whatever constructors. The +reasons for this are varied, but it largely boils down to Rust's philosophy of +*being explicit*. + +Move constructors are meaningless in Rust because we don't enable types to +"care" about their location in memory. Every type must be ready for it to be +blindly memcopied to somewhere else in memory. This means pure on-the-stack-but- +still-movable intrusive linked lists are simply not happening in Rust (safely). + +Assignment and copy constructors similarly don't exist because move semantics +are the only semantics in Rust. At most `x = y` just moves the bits of y into +the x variable. Rust does provide two facilities for providing C++'s copy- +oriented semantics: `Copy` and `Clone`. Clone is our moral equivalent of a copy +constructor, but it's never implicitly invoked. You have to explicitly call +`clone` on an element you want to be cloned. Copy is a special case of Clone +where the implementation is just "copy the bits". Copy types *are* implicitly +cloned whenever they're moved, but because of the definition of Copy this just +means not treating the old copy as uninitialized -- a no-op. + +While Rust provides a `Default` trait for specifying the moral equivalent of a +default constructor, it's incredibly rare for this trait to be used. This is +because variables [aren't implicitly initialized][uninit]. Default is basically +only useful for generic programming. In concrete contexts, a type will provide a +static `new` method for any kind of "default" constructor. This has no relation +to `new` in other languages and has no special meaning. It's just a naming +convention. + +TODO: talk about "placement new"? + +[uninit]: uninitialized.html diff --git a/src/doc/nomicon/conversions.md b/src/doc/nomicon/conversions.md new file mode 100644 index 0000000000..b099a789ec --- /dev/null +++ b/src/doc/nomicon/conversions.md @@ -0,0 +1,34 @@ +% Type Conversions + +At the end of the day, everything is just a pile of bits somewhere, and type +systems are just there to help us use those bits right. There are two common +problems with typing bits: needing to reinterpret those exact bits as a +different type, and needing to change the bits to have equivalent meaning for +a different type. Because Rust encourages encoding important properties in the +type system, these problems are incredibly pervasive. As such, Rust +consequently gives you several ways to solve them. + +First we'll look at the ways that Safe Rust gives you to reinterpret values. +The most trivial way to do this is to just destructure a value into its +constituent parts and then build a new type out of them. e.g. + +```rust +struct Foo { + x: u32, + y: u16, +} + +struct Bar { + a: u32, + b: u16, +} + +fn reinterpret(foo: Foo) -> Bar { + let Foo { x, y } = foo; + Bar { a: x, b: y } +} +``` + +But this is, at best, annoying. For common conversions, Rust provides +more ergonomic alternatives. + diff --git a/src/doc/nomicon/data.md b/src/doc/nomicon/data.md new file mode 100644 index 0000000000..d0a796b7f0 --- /dev/null +++ b/src/doc/nomicon/data.md @@ -0,0 +1,5 @@ +% Data Representation in Rust + +Low-level programming cares a lot about data layout. It's a big deal. It also +pervasively influences the rest of the language, so we're going to start by +digging into how data is represented in Rust. diff --git a/src/doc/nomicon/destructors.md b/src/doc/nomicon/destructors.md new file mode 100644 index 0000000000..568f7c07f5 --- /dev/null +++ b/src/doc/nomicon/destructors.md @@ -0,0 +1,181 @@ +% Destructors + +What the language *does* provide is full-blown automatic destructors through the +`Drop` trait, which provides the following method: + +```rust,ignore +fn drop(&mut self); +``` + +This method gives the type time to somehow finish what it was doing. + +**After `drop` is run, Rust will recursively try to drop all of the fields +of `self`.** + +This is a convenience feature so that you don't have to write "destructor +boilerplate" to drop children. If a struct has no special logic for being +dropped other than dropping its children, then it means `Drop` doesn't need to +be implemented at all! + +**There is no stable way to prevent this behaviour in Rust 1.0.** + +Note that taking `&mut self` means that even if you could suppress recursive +Drop, Rust will prevent you from e.g. moving fields out of self. For most types, +this is totally fine. + +For instance, a custom implementation of `Box` might write `Drop` like this: + +```rust +#![feature(heap_api, core_intrinsics, unique)] + +use std::rt::heap; +use std::ptr::Unique; +use std::intrinsics::drop_in_place; +use std::mem; + +struct Box{ ptr: Unique } + +impl Drop for Box { + fn drop(&mut self) { + unsafe { + drop_in_place(*self.ptr); + heap::deallocate((*self.ptr) as *mut u8, + mem::size_of::(), + mem::align_of::()); + } + } +} +``` + +and this works fine because when Rust goes to drop the `ptr` field it just sees +a [Unique][] that has no actual `Drop` implementation. Similarly nothing can +use-after-free the `ptr` because when drop exits, it becomes inacessible. + +However this wouldn't work: + +```rust +#![feature(heap_api, core_intrinsics, unique)] + +use std::rt::heap; +use std::ptr::Unique; +use std::intrinsics::drop_in_place; +use std::mem; + +struct Box{ ptr: Unique } + +impl Drop for Box { + fn drop(&mut self) { + unsafe { + drop_in_place(*self.ptr); + heap::deallocate((*self.ptr) as *mut u8, + mem::size_of::(), + mem::align_of::()); + } + } +} + +struct SuperBox { my_box: Box } + +impl Drop for SuperBox { + fn drop(&mut self) { + unsafe { + // Hyper-optimized: deallocate the box's contents for it + // without `drop`ing the contents + heap::deallocate((*self.my_box.ptr) as *mut u8, + mem::size_of::(), + mem::align_of::()); + } + } +} +``` + +After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will +happily proceed to tell the box to Drop itself and everything will blow up with +use-after-frees and double-frees. + +Note that the recursive drop behaviour applies to all structs and enums +regardless of whether they implement Drop. Therefore something like + +```rust +struct Boxy { + data1: Box, + data2: Box, + info: u32, +} +``` + +will have its data1 and data2's fields destructors whenever it "would" be +dropped, even though it itself doesn't implement Drop. We say that such a type +*needs Drop*, even though it is not itself Drop. + +Similarly, + +```rust +enum Link { + Next(Box), + None, +} +``` + +will have its inner Box field dropped if and only if an instance stores the +Next variant. + +In general this works really nice because you don't need to worry about +adding/removing drops when you refactor your data layout. Still there's +certainly many valid usecases for needing to do trickier things with +destructors. + +The classic safe solution to overriding recursive drop and allowing moving out +of Self during `drop` is to use an Option: + +```rust +#![feature(heap_api, core_intrinsics, unique)] + +use std::rt::heap; +use std::ptr::Unique; +use std::intrinsics::drop_in_place; +use std::mem; + +struct Box{ ptr: Unique } + +impl Drop for Box { + fn drop(&mut self) { + unsafe { + drop_in_place(*self.ptr); + heap::deallocate((*self.ptr) as *mut u8, + mem::size_of::(), + mem::align_of::()); + } + } +} + +struct SuperBox { my_box: Option> } + +impl Drop for SuperBox { + fn drop(&mut self) { + unsafe { + // Hyper-optimized: deallocate the box's contents for it + // without `drop`ing the contents. Need to set the `box` + // field as `None` to prevent Rust from trying to Drop it. + let my_box = self.my_box.take().unwrap(); + heap::deallocate((*my_box.ptr) as *mut u8, + mem::size_of::(), + mem::align_of::()); + mem::forget(my_box); + } + } +} +``` + +However this has fairly odd semantics: you're saying that a field that *should* +always be Some *may* be None, just because that happens in the destructor. Of +course this conversely makes a lot of sense: you can call arbitrary methods on +self during the destructor, and this should prevent you from ever doing so after +deinitializing the field. Not that it will prevent you from producing any other +arbitrarily invalid state in there. + +On balance this is an ok choice. Certainly what you should reach for by default. +However, in the future we expect there to be a first-class way to announce that +a field shouldn't be automatically dropped. + +[Unique]: phantom-data.html diff --git a/src/doc/nomicon/dot-operator.md b/src/doc/nomicon/dot-operator.md new file mode 100644 index 0000000000..5d2010d15a --- /dev/null +++ b/src/doc/nomicon/dot-operator.md @@ -0,0 +1,6 @@ +% The Dot Operator + +The dot operator will perform a lot of magic to convert types. It will perform +auto-referencing, auto-dereferencing, and coercion until types match. + +TODO: steal information from http://stackoverflow.com/questions/28519997/what-are-rusts-exact-auto-dereferencing-rules/28552082#28552082 diff --git a/src/doc/nomicon/drop-flags.md b/src/doc/nomicon/drop-flags.md new file mode 100644 index 0000000000..1e81c97479 --- /dev/null +++ b/src/doc/nomicon/drop-flags.md @@ -0,0 +1,95 @@ +% Drop Flags + +The examples in the previous section introduce an interesting problem for Rust. +We have seen that's possible to conditionally initialize, deinitialize, and +reinitialize locations of memory totally safely. For Copy types, this isn't +particularly notable since they're just a random pile of bits. However types +with destructors are a different story: Rust needs to know whether to call a +destructor whenever a variable is assigned to, or a variable goes out of scope. +How can it do this with conditional initialization? + +Note that this is not a problem that all assignments need worry about. In +particular, assigning through a dereference unconditionally drops, and assigning +in a `let` unconditionally doesn't drop: + +``` +let mut x = Box::new(0); // let makes a fresh variable, so never need to drop +let y = &mut x; +*y = Box::new(1); // Deref assumes the referent is initialized, so always drops +``` + +This is only a problem when overwriting a previously initialized variable or +one of its subfields. + +It turns out that Rust actually tracks whether a type should be dropped or not +*at runtime*. As a variable becomes initialized and uninitialized, a *drop flag* +for that variable is toggled. When a variable might need to be dropped, this +flag is evaluated to determine if it should be dropped. + +Of course, it is often the case that a value's initialization state can be +statically known at every point in the program. If this is the case, then the +compiler can theoretically generate more efficient code! For instance, straight- +line code has such *static drop semantics*: + +```rust +let mut x = Box::new(0); // x was uninit; just overwrite. +let mut y = x; // y was uninit; just overwrite and make x uninit. +x = Box::new(0); // x was uninit; just overwrite. +y = x; // y was init; Drop y, overwrite it, and make x uninit! + // y goes out of scope; y was init; Drop y! + // x goes out of scope; x was uninit; do nothing. +``` + +Similarly, branched code where all branches have the same behaviour with respect +to initialization has static drop semantics: + +```rust +# let condition = true; +let mut x = Box::new(0); // x was uninit; just overwrite. +if condition { + drop(x) // x gets moved out; make x uninit. +} else { + println!("{}", x); + drop(x) // x gets moved out; make x uninit. +} +x = Box::new(0); // x was uninit; just overwrite. + // x goes out of scope; x was init; Drop x! +``` + +However code like this *requires* runtime information to correctly Drop: + +```rust +# let condition = true; +let x; +if condition { + x = Box::new(0); // x was uninit; just overwrite. + println!("{}", x); +} + // x goes out of scope; x might be uninit; + // check the flag! +``` + +Of course, in this case it's trivial to retrieve static drop semantics: + +```rust +# let condition = true; +if condition { + let x = Box::new(0); + println!("{}", x); +} +``` + +As of Rust 1.0, the drop flags are actually not-so-secretly stashed in a hidden +field of any type that implements Drop. Rust sets the drop flag by overwriting +the entire value with a particular bit pattern. This is pretty obviously Not +The Fastest and causes a bunch of trouble with optimizing code. It's legacy from +a time when you could do much more complex conditional initialization. + +As such work is currently under way to move the flags out onto the stack frame +where they more reasonably belong. Unfortunately, this work will take some time +as it requires fairly substantial changes to the compiler. + +Regardless, Rust programs don't need to worry about uninitialized values on +the stack for correctness. Although they might care for performance. Thankfully, +Rust makes it easy to take control here! Uninitialized values are there, and +you can work with them in Safe Rust, but you're never in danger. diff --git a/src/doc/nomicon/dropck.md b/src/doc/nomicon/dropck.md new file mode 100644 index 0000000000..df09d1a174 --- /dev/null +++ b/src/doc/nomicon/dropck.md @@ -0,0 +1,127 @@ +% Drop Check + +We have seen how lifetimes provide us some fairly simple rules for ensuring +that never read dangling references. However up to this point we have only ever +interacted with the *outlives* relationship in an inclusive manner. That is, +when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as +`'b`. At first glance, this seems to be a meaningless distinction. Nothing ever +gets dropped at the same time as another, right? This is why we used the +following desugarring of `let` statements: + +```rust,ignore +let x; +let y; +``` + +```rust,ignore +{ + let x; + { + let y; + } +} +``` + +Each creates its own scope, clearly establishing that one drops before the +other. However, what if we do the following? + +```rust,ignore +let (x, y) = (vec![], vec![]); +``` + +Does either value strictly outlive the other? The answer is in fact *no*, +neither value strictly outlives the other. Of course, one of x or y will be +dropped before the other, but the actual order is not specified. Tuples aren't +special in this regard; composite structures just don't guarantee their +destruction order as of Rust 1.0. + +We *could* specify this for the fields of built-in composites like tuples and +structs. However, what about something like Vec? Vec has to manually drop its +elements via pure-library code. In general, anything that implements Drop has +a chance to fiddle with its innards during its final death knell. Therefore +the compiler can't sufficiently reason about the actual destruction order +of the contents of any type that implements Drop. + +So why do we care? We care because if the type system isn't careful, it could +accidentally make dangling pointers. Consider the following simple program: + +```rust +struct Inspector<'a>(&'a u8); + +fn main() { + let (inspector, days); + days = Box::new(1); + inspector = Inspector(&days); +} +``` + +This program is totally sound and compiles today. The fact that `days` does +not *strictly* outlive `inspector` doesn't matter. As long as the `inspector` +is alive, so is days. + +However if we add a destructor, the program will no longer compile! + +```rust,ignore +struct Inspector<'a>(&'a u8); + +impl<'a> Drop for Inspector<'a> { + fn drop(&mut self) { + println!("I was only {} days from retirement!", self.0); + } +} + +fn main() { + let (inspector, days); + days = Box::new(1); + inspector = Inspector(&days); + // Let's say `days` happens to get dropped first. + // Then when Inspector is dropped, it will try to read free'd memory! +} +``` + +```text +:12:28: 12:32 error: `days` does not live long enough +:12 inspector = Inspector(&days); + ^~~~ +:9:11: 15:2 note: reference must be valid for the block at 9:10... +:9 fn main() { +:10 let (inspector, days); +:11 days = Box::new(1); +:12 inspector = Inspector(&days); +:13 // Let's say `days` happens to get dropped first. +:14 // Then when Inspector is dropped, it will try to read free'd memory! + ... +:10:27: 15:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 10:26 +:10 let (inspector, days); +:11 days = Box::new(1); +:12 inspector = Inspector(&days); +:13 // Let's say `days` happens to get dropped first. +:14 // Then when Inspector is dropped, it will try to read free'd memory! +:15 } +``` + +Implementing Drop lets the Inspector execute some arbitrary code during its +death. This means it can potentially observe that types that are supposed to +live as long as it does actually were destroyed first. + +Interestingly, only generic types need to worry about this. If they aren't +generic, then the only lifetimes they can harbor are `'static`, which will truly +live *forever*. This is why this problem is referred to as *sound generic drop*. +Sound generic drop is enforced by the *drop checker*. As of this writing, some +of the finer details of how the drop checker validates types is totally up in +the air. However The Big Rule is the subtlety that we have focused on this whole +section: + +**For a generic type to soundly implement drop, its generics arguments must +strictly outlive it.** + +This rule is sufficient but not necessary to satisfy the drop checker. That is, +if your type obeys this rule then it's definitely sound to drop. However +there are special cases where you can fail to satisfy this, but still +successfully pass the borrow checker. These are the precise rules that are +currently up in the air. + +It turns out that when writing unsafe code, we generally don't need to +worry at all about doing the right thing for the drop checker. However there +is one special case that you need to worry about, which we will look at in +the next section. diff --git a/src/doc/nomicon/exception-safety.md b/src/doc/nomicon/exception-safety.md new file mode 100644 index 0000000000..74f7831a72 --- /dev/null +++ b/src/doc/nomicon/exception-safety.md @@ -0,0 +1,217 @@ +% Exception Safety + +Although programs should use unwinding sparingly, there's a lot of code that +*can* panic. If you unwrap a None, index out of bounds, or divide by 0, your +program will panic. On debug builds, every arithmetic operation can panic +if it overflows. Unless you are very careful and tightly control what code runs, +pretty much everything can unwind, and you need to be ready for it. + +Being ready for unwinding is often referred to as *exception safety* +in the broader programming world. In Rust, there are two levels of exception +safety that one may concern themselves with: + +* In unsafe code, we *must* be exception safe to the point of not violating + memory safety. We'll call this *minimal* exception safety. + +* In safe code, it is *good* to be exception safe to the point of your program + doing the right thing. We'll call this *maximal* exception safety. + +As is the case in many places in Rust, Unsafe code must be ready to deal with +bad Safe code when it comes to unwinding. Code that transiently creates +unsound states must be careful that a panic does not cause that state to be +used. Generally this means ensuring that only non-panicking code is run while +these states exist, or making a guard that cleans up the state in the case of +a panic. This does not necessarily mean that the state a panic witnesses is a +fully coherent state. We need only guarantee that it's a *safe* state. + +Most Unsafe code is leaf-like, and therefore fairly easy to make exception-safe. +It controls all the code that runs, and most of that code can't panic. However +it is not uncommon for Unsafe code to work with arrays of temporarily +uninitialized data while repeatedly invoking caller-provided code. Such code +needs to be careful and consider exception safety. + + + + + +## Vec::push_all + +`Vec::push_all` is a temporary hack to get extending a Vec by a slice reliably +efficient without specialization. Here's a simple implementation: + +```rust,ignore +impl Vec { + fn push_all(&mut self, to_push: &[T]) { + self.reserve(to_push.len()); + unsafe { + // can't overflow because we just reserved this + self.set_len(self.len() + to_push.len()); + + for (i, x) in to_push.iter().enumerate() { + self.ptr().offset(i as isize).write(x.clone()); + } + } + } +} +``` + +We bypass `push` in order to avoid redundant capacity and `len` checks on the +Vec that we definitely know has capacity. The logic is totally correct, except +there's a subtle problem with our code: it's not exception-safe! `set_len`, +`offset`, and `write` are all fine; `clone` is the panic bomb we over-looked. + +Clone is completely out of our control, and is totally free to panic. If it +does, our function will exit early with the length of the Vec set too large. If +the Vec is looked at or dropped, uninitialized memory will be read! + +The fix in this case is fairly simple. If we want to guarantee that the values +we *did* clone are dropped, we can set the `len` every loop iteration. If we +just want to guarantee that uninitialized memory can't be observed, we can set +the `len` after the loop. + + + + + +## BinaryHeap::sift_up + +Bubbling an element up a heap is a bit more complicated than extending a Vec. +The pseudocode is as follows: + +```text +bubble_up(heap, index): + while index != 0 && heap[index] < heap[parent(index)]: + heap.swap(index, parent(index)) + index = parent(index) + +``` + +A literal transcription of this code to Rust is totally fine, but has an annoying +performance characteristic: the `self` element is swapped over and over again +uselessly. We would rather have the following: + +```text +bubble_up(heap, index): + let elem = heap[index] + while index != 0 && element < heap[parent(index)]: + heap[index] = heap[parent(index)] + index = parent(index) + heap[index] = elem +``` + +This code ensures that each element is copied as little as possible (it is in +fact necessary that elem be copied twice in general). However it now exposes +some exception safety trouble! At all times, there exists two copies of one +value. If we panic in this function something will be double-dropped. +Unfortunately, we also don't have full control of the code: that comparison is +user-defined! + +Unlike Vec, the fix isn't as easy here. One option is to break the user-defined +code and the unsafe code into two separate phases: + +```text +bubble_up(heap, index): + let end_index = index; + while end_index != 0 && heap[end_index] < heap[parent(end_index)]: + end_index = parent(end_index) + + let elem = heap[index] + while index != end_index: + heap[index] = heap[parent(index)] + index = parent(index) + heap[index] = elem +``` + +If the user-defined code blows up, that's no problem anymore, because we haven't +actually touched the state of the heap yet. Once we do start messing with the +heap, we're working with only data and functions that we trust, so there's no +concern of panics. + +Perhaps you're not happy with this design. Surely it's cheating! And we have +to do the complex heap traversal *twice*! Alright, let's bite the bullet. Let's +intermix untrusted and unsafe code *for reals*. + +If Rust had `try` and `finally` like in Java, we could do the following: + +```text +bubble_up(heap, index): + let elem = heap[index] + try: + while index != 0 && element < heap[parent(index)]: + heap[index] = heap[parent(index)] + index = parent(index) + finally: + heap[index] = elem +``` + +The basic idea is simple: if the comparison panics, we just toss the loose +element in the logically uninitialized index and bail out. Anyone who observes +the heap will see a potentially *inconsistent* heap, but at least it won't +cause any double-drops! If the algorithm terminates normally, then this +operation happens to coincide precisely with the how we finish up regardless. + +Sadly, Rust has no such construct, so we're going to need to roll our own! The +way to do this is to store the algorithm's state in a separate struct with a +destructor for the "finally" logic. Whether we panic or not, that destructor +will run and clean up after us. + +```rust,ignore +struct Hole<'a, T: 'a> { + data: &'a mut [T], + /// `elt` is always `Some` from new until drop. + elt: Option, + pos: usize, +} + +impl<'a, T> Hole<'a, T> { + fn new(data: &'a mut [T], pos: usize) -> Self { + unsafe { + let elt = ptr::read(&data[pos]); + Hole { + data: data, + elt: Some(elt), + pos: pos, + } + } + } + + fn pos(&self) -> usize { self.pos } + + fn removed(&self) -> &T { self.elt.as_ref().unwrap() } + + unsafe fn get(&self, index: usize) -> &T { &self.data[index] } + + unsafe fn move_to(&mut self, index: usize) { + let index_ptr: *const _ = &self.data[index]; + let hole_ptr = &mut self.data[self.pos]; + ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); + self.pos = index; + } +} + +impl<'a, T> Drop for Hole<'a, T> { + fn drop(&mut self) { + // fill the hole again + unsafe { + let pos = self.pos; + ptr::write(&mut self.data[pos], self.elt.take().unwrap()); + } + } +} + +impl BinaryHeap { + fn sift_up(&mut self, pos: usize) { + unsafe { + // Take out the value at `pos` and create a hole. + let mut hole = Hole::new(&mut self.data, pos); + + while hole.pos() != 0 { + let parent = parent(hole.pos()); + if hole.removed() <= hole.get(parent) { break } + hole.move_to(parent); + } + // Hole will be unconditionally filled here; panic or not! + } + } +} +``` diff --git a/src/doc/nomicon/exotic-sizes.md b/src/doc/nomicon/exotic-sizes.md new file mode 100644 index 0000000000..0b653a7ad3 --- /dev/null +++ b/src/doc/nomicon/exotic-sizes.md @@ -0,0 +1,137 @@ +% Exotically Sized Types + +Most of the time, we think in terms of types with a fixed, positive size. This +is not always the case, however. + + + + + +# Dynamically Sized Types (DSTs) + +Rust in fact supports Dynamically Sized Types (DSTs): types without a statically +known size or alignment. On the surface, this is a bit nonsensical: Rust *must* +know the size and alignment of something in order to correctly work with it! In +this regard, DSTs are not normal types. Due to their lack of a statically known +size, these types can only exist behind some kind of pointer. Any pointer to a +DST consequently becomes a *fat* pointer consisting of the pointer and the +information that "completes" them (more on this below). + +There are two major DSTs exposed by the language: trait objects, and slices. + +A trait object represents some type that implements the traits it specifies. +The exact original type is *erased* in favour of runtime reflection +with a vtable containing all the information necessary to use the type. +This is the information that completes a trait object: a pointer to its vtable. + +A slice is simply a view into some contiguous storage -- typically an array or +`Vec`. The information that completes a slice is just the number of elements +it points to. + +Structs can actually store a single DST directly as their last field, but this +makes them a DST as well: + +```rust +// Can't be stored on the stack directly +struct Foo { + info: u32, + data: [u8], +} +``` + +**NOTE: [As of Rust 1.0 struct DSTs are broken if the last field has +a variable position based on its alignment][dst-issue].** + + + + + +# Zero Sized Types (ZSTs) + +Rust actually allows types to be specified that occupy no space: + +```rust +struct Foo; // No fields = no size + +// All fields have no size = no size +struct Baz { + foo: Foo, + qux: (), // empty tuple has no size + baz: [u8; 0], // empty array has no size +} +``` + +On their own, Zero Sized Types (ZSTs) are, for obvious reasons, pretty useless. +However as with many curious layout choices in Rust, their potential is realized +in a generic context: Rust largely understands that any operation that produces +or stores a ZST can be reduced to a no-op. First off, storing it doesn't even +make sense -- it doesn't occupy any space. Also there's only one value of that +type, so anything that loads it can just produce it from the aether -- which is +also a no-op since it doesn't occupy any space. + +One of the most extreme example's of this is Sets and Maps. Given a +`Map`, it is common to implement a `Set` as just a thin wrapper +around `Map`. In many languages, this would necessitate +allocating space for UselessJunk and doing work to store and load UselessJunk +only to discard it. Proving this unnecessary would be a difficult analysis for +the compiler. + +However in Rust, we can just say that `Set = Map`. Now Rust +statically knows that every load and store is useless, and no allocation has any +size. The result is that the monomorphized code is basically a custom +implementation of a HashSet with none of the overhead that HashMap would have to +support values. + +Safe code need not worry about ZSTs, but *unsafe* code must be careful about the +consequence of types with no size. In particular, pointer offsets are no-ops, +and standard allocators (including jemalloc, the one used by default in Rust) +generally consider passing in `0` for the size of an allocation as Undefined +Behaviour. + + + + + +# Empty Types + +Rust also enables types to be declared that *cannot even be instantiated*. These +types can only be talked about at the type level, and never at the value level. +Empty types can be declared by specifying an enum with no variants: + +```rust +enum Void {} // No variants = EMPTY +``` + +Empty types are even more marginal than ZSTs. The primary motivating example for +Void types is type-level unreachability. For instance, suppose an API needs to +return a Result in general, but a specific case actually is infallible. It's +actually possible to communicate this at the type level by returning a +`Result`. Consumers of the API can confidently unwrap such a Result +knowing that it's *statically impossible* for this value to be an `Err`, as +this would require providing a value of type `Void`. + +In principle, Rust can do some interesting analyses and optimizations based +on this fact. For instance, `Result` could be represented as just `T`, +because the `Err` case doesn't actually exist. The following *could* also +compile: + +```rust,ignore +enum Void {} + +let res: Result = Ok(0); + +// Err doesn't exist anymore, so Ok is actually irrefutable. +let Ok(num) = res; +``` + +But neither of these tricks work today, so all Void types get you is +the ability to be confident that certain situations are statically impossible. + +One final subtle detail about empty types is that raw pointers to them are +actually valid to construct, but dereferencing them is Undefined Behaviour +because that doesn't actually make sense. That is, you could model C's `void *` +type with `*const Void`, but this doesn't necessarily gain anything over using +e.g. `*const ()`, which *is* safe to randomly dereference. + + +[dst-issue]: https://github.com/rust-lang/rust/issues/26403 diff --git a/src/doc/nomicon/hrtb.md b/src/doc/nomicon/hrtb.md new file mode 100644 index 0000000000..8692832e2c --- /dev/null +++ b/src/doc/nomicon/hrtb.md @@ -0,0 +1,73 @@ +% Higher-Rank Trait Bounds (HRTBs) + +Rust's `Fn` traits are a little bit magic. For instance, we can write the +following code: + +```rust +struct Closure { + data: (u8, u16), + func: F, +} + +impl Closure + where F: Fn(&(u8, u16)) -> &u8, +{ + fn call(&self) -> &u8 { + (self.func)(&self.data) + } +} + +fn do_it(data: &(u8, u16)) -> &u8 { &data.0 } + +fn main() { + let clo = Closure { data: (0, 1), func: do_it }; + println!("{}", clo.call()); +} +``` + +If we try to naively desugar this code in the same way that we did in the +lifetimes section, we run into some trouble: + +```rust,ignore +struct Closure { + data: (u8, u16), + func: F, +} + +impl Closure + // where F: Fn(&'??? (u8, u16)) -> &'??? u8, +{ + fn call<'a>(&'a self) -> &'a u8 { + (self.func)(&self.data) + } +} + +fn do_it<'b>(data: &'b (u8, u16)) -> &'b u8 { &'b data.0 } + +fn main() { + 'x: { + let clo = Closure { data: (0, 1), func: do_it }; + println!("{}", clo.call()); + } +} +``` + +How on earth are we supposed to express the lifetimes on `F`'s trait bound? We +need to provide some lifetime there, but the lifetime we care about can't be +named until we enter the body of `call`! Also, that isn't some fixed lifetime; +`call` works with *any* lifetime `&self` happens to have at that point. + +This job requires The Magic of Higher-Rank Trait Bounds (HRTBs). The way we +desugar this is as follows: + +```rust,ignore +where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, +``` + +(Where `Fn(a, b, c) -> d` is itself just sugar for the unstable *real* `Fn` +trait) + +`for<'a>` can be read as "for all choices of `'a`", and basically produces an +*infinite list* of trait bounds that F must satisfy. Intense. There aren't many +places outside of the `Fn` traits where we encounter HRTBs, and even for +those we have a nice magic sugar for the common cases. diff --git a/src/doc/nomicon/leaking.md b/src/doc/nomicon/leaking.md new file mode 100644 index 0000000000..1aa78e112e --- /dev/null +++ b/src/doc/nomicon/leaking.md @@ -0,0 +1,252 @@ +% Leaking + +Ownership-based resource management is intended to simplify composition. You +acquire resources when you create the object, and you release the resources when +it gets destroyed. Since destruction is handled for you, it means you can't +forget to release the resources, and it happens as soon as possible! Surely this +is perfect and all of our problems are solved. + +Everything is terrible and we have new and exotic problems to try to solve. + +Many people like to believe that Rust eliminates resource leaks. In practice, +this is basically true. You would be surprised to see a Safe Rust program +leak resources in an uncontrolled way. + +However from a theoretical perspective this is absolutely not the case, no +matter how you look at it. In the strictest sense, "leaking" is so abstract as +to be unpreventable. It's quite trivial to initialize a collection at the start +of a program, fill it with tons of objects with destructors, and then enter an +infinite event loop that never refers to it. The collection will sit around +uselessly, holding on to its precious resources until the program terminates (at +which point all those resources would have been reclaimed by the OS anyway). + +We may consider a more restricted form of leak: failing to drop a value that is +unreachable. Rust also doesn't prevent this. In fact Rust *has a function for +doing this*: `mem::forget`. This function consumes the value it is passed *and +then doesn't run its destructor*. + +In the past `mem::forget` was marked as unsafe as a sort of lint against using +it, since failing to call a destructor is generally not a well-behaved thing to +do (though useful for some special unsafe code). However this was generally +determined to be an untenable stance to take: there are many ways to fail to +call a destructor in safe code. The most famous example is creating a cycle of +reference-counted pointers using interior mutability. + +It is reasonable for safe code to assume that destructor leaks do not happen, as +any program that leaks destructors is probably wrong. However *unsafe* code +cannot rely on destructors to be run in order to be safe. For most types this +doesn't matter: if you leak the destructor then the type is by definition +inaccessible, so it doesn't matter, right? For instance, if you leak a `Box` +then you waste some memory but that's hardly going to violate memory-safety. + +However where we must be careful with destructor leaks are *proxy* types. These +are types which manage access to a distinct object, but don't actually own it. +Proxy objects are quite rare. Proxy objects you'll need to care about are even +rarer. However we'll focus on three interesting examples in the standard +library: + +* `vec::Drain` +* `Rc` +* `thread::scoped::JoinGuard` + + + +## Drain + +`drain` is a collections API that moves data out of the container without +consuming the container. This enables us to reuse the allocation of a `Vec` +after claiming ownership over all of its contents. It produces an iterator +(Drain) that returns the contents of the Vec by-value. + +Now, consider Drain in the middle of iteration: some values have been moved out, +and others haven't. This means that part of the Vec is now full of logically +uninitialized data! We could backshift all the elements in the Vec every time we +remove a value, but this would have pretty catastrophic performance +consequences. + +Instead, we would like Drain to fix the Vec's backing storage when it is +dropped. It should run itself to completion, backshift any elements that weren't +removed (drain supports subranges), and then fix Vec's `len`. It's even +unwinding-safe! Easy! + +Now consider the following: + +```rust,ignore +let mut vec = vec![Box::new(0); 4]; + +{ + // start draining, vec can no longer be accessed + let mut drainer = vec.drain(..); + + // pull out two elements and immediately drop them + drainer.next(); + drainer.next(); + + // get rid of drainer, but don't call its destructor + mem::forget(drainer); +} + +// Oops, vec[0] was dropped, we're reading a pointer into free'd memory! +println!("{}", vec[0]); +``` + +This is pretty clearly Not Good. Unfortunately, we're kind've stuck between a +rock and a hard place: maintaining consistent state at every step has an +enormous cost (and would negate any benefits of the API). Failing to maintain +consistent state gives us Undefined Behaviour in safe code (making the API +unsound). + +So what can we do? Well, we can pick a trivially consistent state: set the Vec's +len to be 0 when we start the iteration, and fix it up if necessary in the +destructor. That way, if everything executes like normal we get the desired +behaviour with minimal overhead. But if someone has the *audacity* to +mem::forget us in the middle of the iteration, all that does is *leak even more* +(and possibly leave the Vec in an unexpected but otherwise consistent state). +Since we've accepted that mem::forget is safe, this is definitely safe. We call +leaks causing more leaks a *leak amplification*. + + + + +## Rc + +Rc is an interesting case because at first glance it doesn't appear to be a +proxy value at all. After all, it manages the data it points to, and dropping +all the Rcs for a value will drop that value. Leaking an Rc doesn't seem like it +would be particularly dangerous. It will leave the refcount permanently +incremented and prevent the data from being freed or dropped, but that seems +just like Box, right? + +Nope. + +Let's consider a simplified implementation of Rc: + +```rust,ignore +struct Rc { + ptr: *mut RcBox, +} + +struct RcBox { + data: T, + ref_count: usize, +} + +impl Rc { + fn new(data: T) -> Self { + unsafe { + // Wouldn't it be nice if heap::allocate worked like this? + let ptr = heap::allocate>(); + ptr::write(ptr, RcBox { + data: data, + ref_count: 1, + }); + Rc { ptr: ptr } + } + } + + fn clone(&self) -> Self { + unsafe { + (*self.ptr).ref_count += 1; + } + Rc { ptr: self.ptr } + } +} + +impl Drop for Rc { + fn drop(&mut self) { + unsafe { + let inner = &mut ; + (*self.ptr).ref_count -= 1; + if (*self.ptr).ref_count == 0 { + // drop the data and then free it + ptr::read(self.ptr); + heap::deallocate(self.ptr); + } + } + } +} +``` + +This code contains an implicit and subtle assumption: `ref_count` can fit in a +`usize`, because there can't be more than `usize::MAX` Rcs in memory. However +this itself assumes that the `ref_count` accurately reflects the number of Rcs +in memory, which we know is false with `mem::forget`. Using `mem::forget` we can +overflow the `ref_count`, and then get it down to 0 with outstanding Rcs. Then +we can happily use-after-free the inner data. Bad Bad Not Good. + +This can be solved by just checking the `ref_count` and doing *something*. The +standard library's stance is to just abort, because your program has become +horribly degenerate. Also *oh my gosh* it's such a ridiculous corner case. + + + + +## thread::scoped::JoinGuard + +The thread::scoped API intends to allow threads to be spawned that reference +data on their parent's stack without any synchronization over that data by +ensuring the parent joins the thread before any of the shared data goes out +of scope. + +```rust,ignore +pub fn scoped<'a, F>(f: F) -> JoinGuard<'a> + where F: FnOnce() + Send + 'a +``` + +Here `f` is some closure for the other thread to execute. Saying that +`F: Send +'a` is saying that it closes over data that lives for `'a`, and it +either owns that data or the data was Sync (implying `&data` is Send). + +Because JoinGuard has a lifetime, it keeps all the data it closes over +borrowed in the parent thread. This means the JoinGuard can't outlive +the data that the other thread is working on. When the JoinGuard *does* get +dropped it blocks the parent thread, ensuring the child terminates before any +of the closed-over data goes out of scope in the parent. + +Usage looked like: + +```rust,ignore +let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +{ + let guards = vec![]; + for x in &mut data { + // Move the mutable reference into the closure, and execute + // it on a different thread. The closure has a lifetime bound + // by the lifetime of the mutable reference `x` we store in it. + // The guard that is returned is in turn assigned the lifetime + // of the closure, so it also mutably borrows `data` as `x` did. + // This means we cannot access `data` until the guard goes away. + let guard = thread::scoped(move || { + *x *= 2; + }); + // store the thread's guard for later + guards.push(guard); + } + // All guards are dropped here, forcing the threads to join + // (this thread blocks here until the others terminate). + // Once the threads join, the borrow expires and the data becomes + // accessible again in this thread. +} +// data is definitely mutated here. +``` + +In principle, this totally works! Rust's ownership system perfectly ensures it! +...except it relies on a destructor being called to be safe. + +```rust,ignore +let mut data = Box::new(0); +{ + let guard = thread::scoped(|| { + // This is at best a data race. At worst, it's also a use-after-free. + *data += 1; + }); + // Because the guard is forgotten, expiring the loan without blocking this + // thread. + mem::forget(guard); +} +// So the Box is dropped here while the scoped thread may or may not be trying +// to access it. +``` + +Dang. Here the destructor running was pretty fundamental to the API, and it had +to be scrapped in favour of a completely different design. diff --git a/src/doc/nomicon/lifetime-elision.md b/src/doc/nomicon/lifetime-elision.md new file mode 100644 index 0000000000..41014f46dd --- /dev/null +++ b/src/doc/nomicon/lifetime-elision.md @@ -0,0 +1,64 @@ +% Lifetime Elision + +In order to make common patterns more ergonomic, Rust allows lifetimes to be +*elided* in function signatures. + +A *lifetime position* is anywhere you can write a lifetime in a type: + +```rust,ignore +&'a T +&'a mut T +T<'a> +``` + +Lifetime positions can appear as either "input" or "output": + +* For `fn` definitions, input refers to the types of the formal arguments + in the `fn` definition, while output refers to + result types. So `fn foo(s: &str) -> (&str, &str)` has elided one lifetime in + input position and two lifetimes in output position. + Note that the input positions of a `fn` method definition do not + include the lifetimes that occur in the method's `impl` header + (nor lifetimes that occur in the trait header, for a default method). + +* In the future, it should be possible to elide `impl` headers in the same manner. + +Elision rules are as follows: + +* Each elided lifetime in input position becomes a distinct lifetime + parameter. + +* If there is exactly one input lifetime position (elided or not), that lifetime + is assigned to *all* elided output lifetimes. + +* If there are multiple input lifetime positions, but one of them is `&self` or + `&mut self`, the lifetime of `self` is assigned to *all* elided output lifetimes. + +* Otherwise, it is an error to elide an output lifetime. + +Examples: + +```rust,ignore +fn print(s: &str); // elided +fn print<'a>(s: &'a str); // expanded + +fn debug(lvl: uint, s: &str); // elided +fn debug<'a>(lvl: uint, s: &'a str); // expanded + +fn substr(s: &str, until: uint) -> &str; // elided +fn substr<'a>(s: &'a str, until: uint) -> &'a str; // expanded + +fn get_str() -> &str; // ILLEGAL + +fn frob(s: &str, t: &str) -> &str; // ILLEGAL + +fn get_mut(&mut self) -> &mut T; // elided +fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded + +fn args(&mut self, args: &[T]) -> &mut Command // elided +fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded + +fn new(buf: &mut [u8]) -> BufWriter; // elided +fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded + +``` diff --git a/src/doc/nomicon/lifetime-mismatch.md b/src/doc/nomicon/lifetime-mismatch.md new file mode 100644 index 0000000000..8b01616ee0 --- /dev/null +++ b/src/doc/nomicon/lifetime-mismatch.md @@ -0,0 +1,81 @@ +% Limits of Lifetimes + +Given the following code: + +```rust,ignore +struct Foo; + +impl Foo { + fn mutate_and_share(&mut self) -> &Self { &*self } + fn share(&self) {} +} + +fn main() { + let mut foo = Foo; + let loan = foo.mutate_and_share(); + foo.share(); +} +``` + +One might expect it to compile. We call `mutate_and_share`, which mutably borrows +`foo` temporarily, but then returns only a shared reference. Therefore we +would expect `foo.share()` to succeed as `foo` shouldn't be mutably borrowed. + +However when we try to compile it: + +```text +:11:5: 11:8 error: cannot borrow `foo` as immutable because it is also borrowed as mutable +:11 foo.share(); + ^~~ +:10:16: 10:19 note: previous borrow of `foo` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foo` until the borrow ends +:10 let loan = foo.mutate_and_share(); + ^~~ +:12:2: 12:2 note: previous borrow ends here +:8 fn main() { +:9 let mut foo = Foo; +:10 let loan = foo.mutate_and_share(); +:11 foo.share(); +:12 } + ^ +``` + +What happened? Well, we got the exact same reasoning as we did for +[Example 2 in the previous section][ex2]. We desugar the program and we get +the following: + +```rust,ignore +struct Foo; + +impl Foo { + fn mutate_and_share<'a>(&'a mut self) -> &'a Self { &'a *self } + fn share<'a>(&'a self) {} +} + +fn main() { + 'b: { + let mut foo: Foo = Foo; + 'c: { + let loan: &'c Foo = Foo::mutate_and_share::<'c>(&'c mut foo); + 'd: { + Foo::share::<'d>(&'d foo); + } + } + } +} +``` + +The lifetime system is forced to extend the `&mut foo` to have lifetime `'c`, +due to the lifetime of `loan` and mutate_and_share's signature. Then when we +try to call `share`, and it sees we're trying to alias that `&'c mut foo` and +blows up in our face! + +This program is clearly correct according to the reference semantics we actually +care about, but the lifetime system is too coarse-grained to handle that. + + +TODO: other common problems? SEME regions stuff, mostly? + + + + +[ex2]: lifetimes.html#example-2:-aliasing-a-mutable-reference diff --git a/src/doc/nomicon/lifetimes.md b/src/doc/nomicon/lifetimes.md new file mode 100644 index 0000000000..6f711d52ea --- /dev/null +++ b/src/doc/nomicon/lifetimes.md @@ -0,0 +1,215 @@ +% Lifetimes + +Rust enforces these rules through *lifetimes*. Lifetimes are effectively +just names for scopes somewhere in the program. Each reference, +and anything that contains a reference, is tagged with a lifetime specifying +the scope it's valid for. + +Within a function body, Rust generally doesn't let you explicitly name the +lifetimes involved. This is because it's generally not really necessary +to talk about lifetimes in a local context; Rust has all the information and +can work out everything as optimally as possible. Many anonymous scopes and +temporaries that you would otherwise have to write are often introduced to +make your code Just Work. + +However once you cross the function boundary, you need to start talking about +lifetimes. Lifetimes are denoted with an apostrophe: `'a`, `'static`. To dip +our toes with lifetimes, we're going to pretend that we're actually allowed +to label scopes with lifetimes, and desugar the examples from the start of +this chapter. + +Originally, our examples made use of *aggressive* sugar -- high fructose corn +syrup even -- around scopes and lifetimes, because writing everything out +explicitly is *extremely noisy*. All Rust code relies on aggressive inference +and elision of "obvious" things. + +One particularly interesting piece of sugar is that each `let` statement implicitly +introduces a scope. For the most part, this doesn't really matter. However it +does matter for variables that refer to each other. As a simple example, let's +completely desugar this simple piece of Rust code: + +```rust +let x = 0; +let y = &x; +let z = &y; +``` + +The borrow checker always tries to minimize the extent of a lifetime, so it will +likely desugar to the following: + +```rust,ignore +// NOTE: `'a: {` and `&'b x` is not valid syntax! +'a: { + let x: i32 = 0; + 'b: { + // lifetime used is 'b because that's good enough. + let y: &'b i32 = &'b x; + 'c: { + // ditto on 'c + let z: &'c &'b i32 = &'c y; + } + } +} +``` + +Wow. That’s... awful. Let’s all take a moment to thank Rust for making this easier. + +Actually passing references to outer scopes will cause Rust to infer +a larger lifetime: + +```rust +let x = 0; +let z; +let y = &x; +z = y; +``` + +```rust,ignore +'a: { + let x: i32 = 0; + 'b: { + let z: &'b i32; + 'c: { + // Must use 'b here because this reference is + // being passed to that scope. + let y: &'b i32 = &'b x; + z = y; + } + } +} +``` + + + +# Example: references that outlive referents + +Alright, let's look at some of those examples from before: + +```rust,ignore +fn as_str(data: &u32) -> &str { + let s = format!("{}", data); + &s +} +``` + +desugars to: + +```rust,ignore +fn as_str<'a>(data: &'a u32) -> &'a str { + 'b: { + let s = format!("{}", data); + return &'a s; + } +} +``` + +This signature of `as_str` takes a reference to a u32 with *some* lifetime, and +promises that it can produce a reference to a str that can live *just as long*. +Already we can see why this signature might be trouble. That basically implies +that we're going to find a str somewhere in the scope the reference +to the u32 originated in, or somewhere *even earlier*. That's a bit of a big +ask. + +We then proceed to compute the string `s`, and return a reference to it. Since +the contract of our function says the reference must outlive `'a`, that's the +lifetime we infer for the reference. Unfortunately, `s` was defined in the +scope `'b`, so the only way this is sound is if `'b` contains `'a` -- which is +clearly false since `'a` must contain the function call itself. We have therefore +created a reference whose lifetime outlives its referent, which is *literally* +the first thing we said that references can't do. The compiler rightfully blows +up in our face. + +To make this more clear, we can expand the example: + +```rust,ignore +fn as_str<'a>(data: &'a u32) -> &'a str { + 'b: { + let s = format!("{}", data); + return &'a s + } +} + +fn main() { + 'c: { + let x: u32 = 0; + 'd: { + // An anonymous scope is introduced because the borrow does not + // need to last for the whole scope x is valid for. The return + // of as_str must find a str somewhere before this function + // call. Obviously not happening. + println!("{}", as_str::<'d>(&'d x)); + } + } +} +``` + +Shoot! + +Of course, the right way to write this function is as follows: + +```rust +fn to_string(data: &u32) -> String { + format!("{}", data) +} +``` + +We must produce an owned value inside the function to return it! The only way +we could have returned an `&'a str` would have been if it was in a field of the +`&'a u32`, which is obviously not the case. + +(Actually we could have also just returned a string literal, which as a global +can be considered to reside at the bottom of the stack; though this limits +our implementation *just a bit*.) + + + + + +# Example: aliasing a mutable reference + +How about the other example: + +```rust,ignore +let mut data = vec![1, 2, 3]; +let x = &data[0]; +data.push(4); +println!("{}", x); +``` + +```rust,ignore +'a: { + let mut data: Vec = vec![1, 2, 3]; + 'b: { + // 'b is as big as we need this borrow to be + // (just need to get to `println!`) + let x: &'b i32 = Index::index::<'b>(&'b data, 0); + 'c: { + // Temporary scope because we don't need the + // &mut to last any longer. + Vec::push(&'c mut data, 4); + } + println!("{}", x); + } +} +``` + +The problem here is is bit more subtle and interesting. We want Rust to +reject this program for the following reason: We have a live shared reference `x` +to a descendent of `data` when we try to take a mutable reference to `data` +to `push`. This would create an aliased mutable reference, which would +violate the *second* rule of references. + +However this is *not at all* how Rust reasons that this program is bad. Rust +doesn't understand that `x` is a reference to a subpath of `data`. It doesn't +understand Vec at all. What it *does* see is that `x` has to live for `'b` to +be printed. The signature of `Index::index` subsequently demands that the +reference we take to `data` has to survive for `'b`. When we try to call `push`, +it then sees us try to make an `&'c mut data`. Rust knows that `'c` is contained +within `'b`, and rejects our program because the `&'b data` must still be live! + +Here we see that the lifetime system is much more coarse than the reference +semantics we're actually interested in preserving. For the most part, *that's +totally ok*, because it keeps us from spending all day explaining our program +to the compiler. However it does mean that several programs that are totally +correct with respect to Rust's *true* semantics are rejected because lifetimes +are too dumb. diff --git a/src/doc/nomicon/meet-safe-and-unsafe.md b/src/doc/nomicon/meet-safe-and-unsafe.md new file mode 100644 index 0000000000..15e49c747b --- /dev/null +++ b/src/doc/nomicon/meet-safe-and-unsafe.md @@ -0,0 +1,98 @@ +% Meet Safe and Unsafe + +Programmers in safe "high-level" languages face a fundamental dilemma. On one +hand, it would be *really* great to just say what you want and not worry about +how it's done. On the other hand, that can lead to unacceptably poor +performance. It may be necessary to drop down to less clear or idiomatic +practices to get the performance characteristics you want. Or maybe you just +throw up your hands in disgust and decide to shell out to an implementation in +a less sugary-wonderful *unsafe* language. + +Worse, when you want to talk directly to the operating system, you *have* to +talk to an unsafe language: *C*. C is ever-present and unavoidable. It's the +lingua-franca of the programming world. +Even other safe languages generally expose C interfaces for the world at large! +Regardless of why you're doing it, as soon as your program starts talking to +C it stops being safe. + +With that said, Rust is *totally* a safe programming language. + +Well, Rust *has* a safe programming language. Let's step back a bit. + +Rust can be thought of as being composed of two programming languages: *Safe +Rust* and *Unsafe Rust*. Safe Rust is For Reals Totally Safe. Unsafe Rust, +unsurprisingly, is *not* For Reals Totally Safe. In fact, Unsafe Rust lets you +do some really crazy unsafe things. + +Safe Rust is the *true* Rust programming language. If all you do is write Safe +Rust, you will never have to worry about type-safety or memory-safety. You will +never endure a null or dangling pointer, or any of that Undefined Behaviour +nonsense. + +*That's totally awesome.* + +The standard library also gives you enough utilities out-of-the-box that you'll +be able to write awesome high-performance applications and libraries in pure +idiomatic Safe Rust. + +But maybe you want to talk to another language. Maybe you're writing a +low-level abstraction not exposed by the standard library. Maybe you're +*writing* the standard library (which is written entirely in Rust). Maybe you +need to do something the type-system doesn't understand and just *frob some dang +bits*. Maybe you need Unsafe Rust. + +Unsafe Rust is exactly like Safe Rust with all the same rules and semantics. +However Unsafe Rust lets you do some *extra* things that are Definitely Not Safe. + +The only things that are different in Unsafe Rust are that you can: + +* Dereference raw pointers +* Call `unsafe` functions (including C functions, intrinsics, and the raw allocator) +* Implement `unsafe` traits +* Mutate statics + +That's it. The reason these operations are relegated to Unsafe is that misusing +any of these things will cause the ever dreaded Undefined Behaviour. Invoking +Undefined Behaviour gives the compiler full rights to do arbitrarily bad things +to your program. You definitely *should not* invoke Undefined Behaviour. + +Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core +language cares about is preventing the following things: + +* Dereferencing null or dangling pointers +* Reading [uninitialized memory][] +* Breaking the [pointer aliasing rules][] +* Producing invalid primitive values: + * dangling/null references + * a `bool` that isn't 0 or 1 + * an undefined `enum` discriminant + * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] + * A non-utf8 `str` +* Unwinding into another language +* Causing a [data race][race] + +That's it. That's all the causes of Undefined Behaviour baked into Rust. Of +course, unsafe functions and traits are free to declare arbitrary other +constraints that a program must maintain to avoid Undefined Behaviour. However, +generally violations of these constraints will just transitively lead to one of +the above problems. Some additional constraints may also derive from compiler +intrinsics that make special assumptions about how code can be optimized. + +Rust is otherwise quite permissive with respect to other dubious operations. +Rust considers it "safe" to: + +* Deadlock +* Have a [race condition][race] +* Leak memory +* Fail to call destructors +* Overflow integers +* Abort the program +* Delete the production database + +However any program that actually manages to do such a thing is *probably* +incorrect. Rust provides lots of tools to make these things rare, but +these problems are considered impractical to categorically prevent. + +[pointer aliasing rules]: references.html +[uninitialized memory]: uninitialized.html +[race]: races.html diff --git a/src/doc/nomicon/obrm.md b/src/doc/nomicon/obrm.md new file mode 100644 index 0000000000..2c495240c1 --- /dev/null +++ b/src/doc/nomicon/obrm.md @@ -0,0 +1,14 @@ +% The Perils Of Ownership Based Resource Management (OBRM) + +OBRM (AKA RAII: Resource Acquisition Is Initialization) is something you'll +interact with a lot in Rust. Especially if you use the standard library. + +Roughly speaking the pattern is as follows: to acquire a resource, you create an +object that manages it. To release the resource, you simply destroy the object, +and it cleans up the resource for you. The most common "resource" this pattern +manages is simply *memory*. `Box`, `Rc`, and basically everything in +`std::collections` is a convenience to enable correctly managing memory. This is +particularly important in Rust because we have no pervasive GC to rely on for +memory management. Which is the point, really: Rust is about control. However we +are not limited to just memory. Pretty much every other system resource like a +thread, file, or socket is exposed through this kind of API. diff --git a/src/doc/nomicon/other-reprs.md b/src/doc/nomicon/other-reprs.md new file mode 100644 index 0000000000..93ef2c13cd --- /dev/null +++ b/src/doc/nomicon/other-reprs.md @@ -0,0 +1,76 @@ +% Alternative representations + +Rust allows you to specify alternative data layout strategies from the default. + + + + +# repr(C) + +This is the most important `repr`. It has fairly simple intent: do what C does. +The order, size, and alignment of fields is exactly what you would expect from C +or C++. Any type you expect to pass through an FFI boundary should have +`repr(C)`, as C is the lingua-franca of the programming world. This is also +necessary to soundly do more elaborate tricks with data layout such as +reinterpreting values as a different type. + +However, the interaction with Rust's more exotic data layout features must be +kept in mind. Due to its dual purpose as "for FFI" and "for layout control", +`repr(C)` can be applied to types that will be nonsensical or problematic if +passed through the FFI boundary. + +* ZSTs are still zero-sized, even though this is not a standard behaviour in +C, and is explicitly contrary to the behaviour of an empty type in C++, which +still consumes a byte of space. + +* DSTs, tuples, and tagged unions are not a concept in C and as such are never +FFI safe. + +* **If the type would have any [drop flags][], they will still be added** + +* This is equivalent to one of `repr(u*)` (see the next section) for enums. The +chosen size is the default enum size for the target platform's C ABI. Note that +enum representation in C is implementation defined, so this is really a "best +guess". In particular, this may be incorrect when the C code of interest is +compiled with certain flags. + + + +# repr(u8), repr(u16), repr(u32), repr(u64) + +These specify the size to make a C-like enum. If the discriminant overflows the +integer it has to fit in, it will produce a compile-time error. You can manually +ask Rust to allow this by setting the overflowing element to explicitly be 0. +However Rust will not allow you to create an enum where two variants have the +same discriminant. + +On non-C-like enums, this will inhibit certain optimizations like the null- +pointer optimization. + +These reprs have no effect on a struct. + + + + +# repr(packed) + +`repr(packed)` forces rust to strip any padding, and only align the type to a +byte. This may improve the memory footprint, but will likely have other negative +side-effects. + +In particular, most architectures *strongly* prefer values to be aligned. This +may mean the unaligned loads are penalized (x86), or even fault (some ARM +chips). For simple cases like directly loading or storing a packed field, the +compiler might be able to paper over alignment issues with shifts and masks. +However if you take a reference to a packed field, it's unlikely that the +compiler will be able to emit code to avoid an unaligned load. + +**[As of Rust 1.0 this can cause undefined behaviour.][ub loads]** + +`repr(packed)` is not to be used lightly. Unless you have extreme requirements, +this should not be used. + +This repr is a modifier on `repr(C)` and `repr(rust)`. + +[drop flags]: drop-flags.html +[ub loads]: https://github.com/rust-lang/rust/issues/27060 diff --git a/src/doc/nomicon/ownership.md b/src/doc/nomicon/ownership.md new file mode 100644 index 0000000000..e80c64c354 --- /dev/null +++ b/src/doc/nomicon/ownership.md @@ -0,0 +1,67 @@ +% Ownership and Lifetimes + +Ownership is the breakout feature of Rust. It allows Rust to be completely +memory-safe and efficient, while avoiding garbage collection. Before getting +into the ownership system in detail, we will consider the motivation of this +design. + +We will assume that you accept that garbage collection (GC) is not always an +optimal solution, and that it is desirable to manually manage memory in some +contexts. If you do not accept this, might I interest you in a different +language? + +Regardless of your feelings on GC, it is pretty clearly a *massive* boon to +making code safe. You never have to worry about things going away *too soon* +(although whether you still wanted to be pointing at that thing is a different +issue...). This is a pervasive problem that C and C++ programs need to deal +with. Consider this simple mistake that all of us who have used a non-GC'd +language have made at one point: + +```rust,ignore +fn as_str(data: &u32) -> &str { + // compute the string + let s = format!("{}", data); + + // OH NO! We returned a reference to something that + // exists only in this function! + // Dangling pointer! Use after free! Alas! + // (this does not compile in Rust) + &s +} +``` + +This is exactly what Rust's ownership system was built to solve. +Rust knows the scope in which the `&s` lives, and as such can prevent it from +escaping. However this is a simple case that even a C compiler could plausibly +catch. Things get more complicated as code gets bigger and pointers get fed through +various functions. Eventually, a C compiler will fall down and won't be able to +perform sufficient escape analysis to prove your code unsound. It will consequently +be forced to accept your program on the assumption that it is correct. + +This will never happen to Rust. It's up to the programmer to prove to the +compiler that everything is sound. + +Of course, Rust's story around ownership is much more complicated than just +verifying that references don't escape the scope of their referent. That's +because ensuring pointers are always valid is much more complicated than this. +For instance in this code, + +```rust,ignore +let mut data = vec![1, 2, 3]; +// get an internal reference +let x = &data[0]; + +// OH NO! `push` causes the backing storage of `data` to be reallocated. +// Dangling pointer! User after free! Alas! +// (this does not compile in Rust) +data.push(4); + +println!("{}", x); +``` + +naive scope analysis would be insufficient to prevent this bug, because `data` +does in fact live as long as we needed. However it was *changed* while we had +a reference into it. This is why Rust requires any references to freeze the +referent and its owners. + + diff --git a/src/doc/nomicon/phantom-data.md b/src/doc/nomicon/phantom-data.md new file mode 100644 index 0000000000..0d7ec7f161 --- /dev/null +++ b/src/doc/nomicon/phantom-data.md @@ -0,0 +1,87 @@ +% PhantomData + +When working with unsafe code, we can often end up in a situation where +types or lifetimes are logically associated with a struct, but not actually +part of a field. This most commonly occurs with lifetimes. For instance, the +`Iter` for `&'a [T]` is (approximately) defined as follows: + +```rust,ignore +struct Iter<'a, T: 'a> { + ptr: *const T, + end: *const T, +} +``` + +However because `'a` is unused within the struct's body, it's *unbounded*. +Because of the troubles this has historically caused, unbounded lifetimes and +types are *forbidden* in struct definitions. Therefore we must somehow refer +to these types in the body. Correctly doing this is necessary to have +correct variance and drop checking. + +We do this using `PhantomData`, which is a special marker type. `PhantomData` +consumes no space, but simulates a field of the given type for the purpose of +static analysis. This was deemed to be less error-prone than explicitly telling +the type-system the kind of variance that you want, while also providing other +useful such as the information needed by drop check. + +Iter logically contains a bunch of `&'a T`s, so this is exactly what we tell +the PhantomData to simulate: + +``` +use std::marker; + +struct Iter<'a, T: 'a> { + ptr: *const T, + end: *const T, + _marker: marker::PhantomData<&'a T>, +} +``` + +and that's it. The lifetime will be bounded, and your iterator will be variant +over `'a` and `T`. Everything Just Works. + +Another important example is Vec, which is (approximately) defined as follows: + +``` +struct Vec { + data: *const T, // *const for variance! + len: usize, + cap: usize, +} +``` + +Unlike the previous example it *appears* that everything is exactly as we +want. Every generic argument to Vec shows up in the at least one field. +Good to go! + +Nope. + +The drop checker will generously determine that Vec does not own any values +of type T. This will in turn make it conclude that it doesn't need to worry +about Vec dropping any T's in its destructor for determining drop check +soundness. This will in turn allow people to create unsoundness using +Vec's destructor. + +In order to tell dropck that we *do* own values of type T, and therefore may +drop some T's when *we* drop, we must add an extra PhantomData saying exactly +that: + +``` +use std::marker; + +struct Vec { + data: *const T, // *const for covariance! + len: usize, + cap: usize, + _marker: marker::PhantomData, +} +``` + +Raw pointers that own an allocation is such a pervasive pattern that the +standard library made a utility for itself called `Unique` which: + +* wraps a `*const T` for variance +* includes a `PhantomData`, +* auto-derives Send/Sync as if T was contained +* marks the pointer as NonZero for the null-pointer optimization + diff --git a/src/doc/nomicon/poisoning.md b/src/doc/nomicon/poisoning.md new file mode 100644 index 0000000000..70de91af61 --- /dev/null +++ b/src/doc/nomicon/poisoning.md @@ -0,0 +1,35 @@ +% Poisoning + +Although all unsafe code *must* ensure it has minimal exception safety, not all +types ensure *maximal* exception safety. Even if the type does, your code may +ascribe additional meaning to it. For instance, an integer is certainly +exception-safe, but has no semantics on its own. It's possible that code that +panics could fail to correctly update the integer, producing an inconsistent +program state. + +This is *usually* fine, because anything that witnesses an exception is about +to get destroyed. For instance, if you send a Vec to another thread and that +thread panics, it doesn't matter if the Vec is in a weird state. It will be +dropped and go away forever. However some types are especially good at smuggling +values across the panic boundary. + +These types may choose to explicitly *poison* themselves if they witness a panic. +Poisoning doesn't entail anything in particular. Generally it just means +preventing normal usage from proceeding. The most notable example of this is the +standard library's Mutex type. A Mutex will poison itself if one of its +MutexGuards (the thing it returns when a lock is obtained) is dropped during a +panic. Any future attempts to lock the Mutex will return an `Err` or panic. + +Mutex poisons not for true safety in the sense that Rust normally cares about. It +poisons as a safety-guard against blindly using the data that comes out of a Mutex +that has witnessed a panic while locked. The data in such a Mutex was likely in the +middle of being modified, and as such may be in an inconsistent or incomplete state. +It is important to note that one cannot violate memory safety with such a type +if it is correctly written. After all, it must be minimally exception-safe! + +However if the Mutex contained, say, a BinaryHeap that does not actually have the +heap property, it's unlikely that any code that uses it will do +what the author intended. As such, the program should not proceed normally. +Still, if you're double-plus-sure that you can do *something* with the value, +the Mutex exposes a method to get the lock anyway. It *is* safe, after all. +Just maybe nonsense. diff --git a/src/doc/nomicon/races.md b/src/doc/nomicon/races.md new file mode 100644 index 0000000000..3b47502ebf --- /dev/null +++ b/src/doc/nomicon/races.md @@ -0,0 +1,86 @@ +% Data Races and Race Conditions + +Safe Rust guarantees an absence of data races, which are defined as: + +* two or more threads concurrently accessing a location of memory +* one of them is a write +* one of them is unsynchronized + +A data race has Undefined Behaviour, and is therefore impossible to perform +in Safe Rust. Data races are *mostly* prevented through rust's ownership system: +it's impossible to alias a mutable reference, so it's impossible to perform a +data race. Interior mutability makes this more complicated, which is largely why +we have the Send and Sync traits (see below). + +**However Rust does not prevent general race conditions.** + +This is pretty fundamentally impossible, and probably honestly undesirable. Your +hardware is racy, your OS is racy, the other programs on your computer are racy, +and the world this all runs in is racy. Any system that could genuinely claim to +prevent *all* race conditions would be pretty awful to use, if not just +incorrect. + +So it's perfectly "fine" for a Safe Rust program to get deadlocked or do +something incredibly stupid with incorrect synchronization. Obviously such a +program isn't very good, but Rust can only hold your hand so far. Still, a +race condition can't violate memory safety in a Rust program on +its own. Only in conjunction with some other unsafe code can a race condition +actually violate memory safety. For instance: + +```rust,no_run +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +let data = vec![1, 2, 3, 4]; +// Arc so that the memory the AtomicUsize is stored in still exists for +// the other thread to increment, even if we completely finish executing +// before it. Rust won't compile the program without it, because of the +// lifetime requirements of thread::spawn! +let idx = Arc::new(AtomicUsize::new(0)); +let other_idx = idx.clone(); + +// `move` captures other_idx by-value, moving it into this thread +thread::spawn(move || { + // It's ok to mutate idx because this value + // is an atomic, so it can't cause a Data Race. + other_idx.fetch_add(10, Ordering::SeqCst); +}); + +// Index with the value loaded from the atomic. This is safe because we +// read the atomic memory only once, and then pass a copy of that value +// to the Vec's indexing implementation. This indexing will be correctly +// bounds checked, and there's no chance of the value getting changed +// in the middle. However our program may panic if the thread we spawned +// managed to increment before this ran. A race condition because correct +// program execution (panicing is rarely correct) depends on order of +// thread execution. +println!("{}", data[idx.load(Ordering::SeqCst)]); +``` + +```rust,no_run +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +let data = vec![1, 2, 3, 4]; + +let idx = Arc::new(AtomicUsize::new(0)); +let other_idx = idx.clone(); + +// `move` captures other_idx by-value, moving it into this thread +thread::spawn(move || { + // It's ok to mutate idx because this value + // is an atomic, so it can't cause a Data Race. + other_idx.fetch_add(10, Ordering::SeqCst); +}); + +if idx.load(Ordering::SeqCst) < data.len() { + unsafe { + // Incorrectly loading the idx after we did the bounds check. + // It could have changed. This is a race condition, *and dangerous* + // because we decided to do `get_unchecked`, which is `unsafe`. + println!("{}", data.get_unchecked(idx.load(Ordering::SeqCst))); + } +} +``` diff --git a/src/doc/nomicon/references.md b/src/doc/nomicon/references.md new file mode 100644 index 0000000000..3d7369eca0 --- /dev/null +++ b/src/doc/nomicon/references.md @@ -0,0 +1,177 @@ +% References + +This section gives a high-level view of the memory model that *all* Rust +programs must satisfy to be correct. Safe code is statically verified +to obey this model by the borrow checker. Unsafe code may go above +and beyond the borrow checker while still satisfying this model. The borrow +checker may also be extended to allow more programs to compile, as long as +this more fundamental model is satisfied. + +There are two kinds of reference: + +* Shared reference: `&` +* Mutable reference: `&mut` + +Which obey the following rules: + +* A reference cannot outlive its referent +* A mutable reference cannot be aliased + +That's it. That's the whole model. Of course, we should probably define +what *aliased* means. To define aliasing, we must define the notion of +*paths* and *liveness*. + + +**NOTE: The model that follows is generally agreed to be dubious and have +issues. It's ok-ish as an intuitive model, but fails to capture the desired +semantics. We leave this here to be able to use notions introduced here in later +sections. This will be significantly changed in the future. TODO: do that.** + + +# Paths + +If all Rust had were values (no pointers), then every value would be uniquely +owned by a variable or composite structure. From this we naturally derive a +*tree* of ownership. The stack itself is the root of the tree, with every +variable as its direct children. Each variable's direct children would be their +fields (if any), and so on. + +From this view, every value in Rust has a unique *path* in the tree of +ownership. Of particular interest are *ancestors* and *descendants*: if `x` owns +`y`, then `x` is an ancestor of `y`, and `y` is a descendant of `x`. Note +that this is an inclusive relationship: `x` is a descendant and ancestor of +itself. + +We can then define references as simply *names* for paths. When you create a +reference, you're declaring that an ownership path exists to this address +of memory. + +Tragically, plenty of data doesn't reside on the stack, and we must also +accommodate this. Globals and thread-locals are simple enough to model as +residing at the bottom of the stack (though we must be careful with mutable +globals). Data on the heap poses a different problem. + +If all Rust had on the heap was data uniquely owned by a pointer on the stack, +then we could just treat such a pointer as a struct that owns the value on the +heap. Box, Vec, String, and HashMap, are examples of types which uniquely +own data on the heap. + +Unfortunately, data on the heap is not *always* uniquely owned. Rc for instance +introduces a notion of *shared* ownership. Shared ownership of a value means +there is no unique path to it. A value with no unique path limits what we can do +with it. + +In general, only shared references can be created to non-unique paths. However +mechanisms which ensure mutual exclusion may establish One True Owner +temporarily, establishing a unique path to that value (and therefore all +its children). If this is done, the value may be mutated. In particular, a +mutable reference can be taken. + +The most common way to establish such a path is through *interior mutability*, +in contrast to the *inherited mutability* that everything in Rust normally uses. +Cell, RefCell, Mutex, and RWLock are all examples of interior mutability types. +These types provide exclusive access through runtime restrictions. + +An interesting case of this effect is Rc itself: if an Rc has refcount 1, +then it is safe to mutate or even move its internals. Note however that the +refcount itself uses interior mutability. + +In order to correctly communicate to the type system that a variable or field of +a struct can have interior mutability, it must be wrapped in an UnsafeCell. This +does not in itself make it safe to perform interior mutability operations on +that value. You still must yourself ensure that mutual exclusion is upheld. + + + + +# Liveness + +Note: Liveness is not the same thing as a *lifetime*, which will be explained +in detail in the next section of this chapter. + +Roughly, a reference is *live* at some point in a program if it can be +dereferenced. Shared references are always live unless they are literally +unreachable (for instance, they reside in freed or leaked memory). Mutable +references can be reachable but *not* live through the process of *reborrowing*. + +A mutable reference can be reborrowed to either a shared or mutable reference to +one of its descendants. A reborrowed reference will only be live again once all +reborrows derived from it expire. For instance, a mutable reference can be +reborrowed to point to a field of its referent: + +```rust +let x = &mut (1, 2); +{ + // reborrow x to a subfield + let y = &mut x.0; + // y is now live, but x isn't + *y = 3; +} +// y goes out of scope, so x is live again +*x = (5, 7); +``` + +It is also possible to reborrow into *multiple* mutable references, as long as +they are *disjoint*: no reference is an ancestor of another. Rust +explicitly enables this to be done with disjoint struct fields, because +disjointness can be statically proven: + +```rust +let x = &mut (1, 2); +{ + // reborrow x to two disjoint subfields + let y = &mut x.0; + let z = &mut x.1; + + // y and z are now live, but x isn't + *y = 3; + *z = 4; +} +// y and z go out of scope, so x is live again +*x = (5, 7); +``` + +However it's often the case that Rust isn't sufficiently smart to prove that +multiple borrows are disjoint. *This does not mean it is fundamentally illegal +to make such a borrow*, just that Rust isn't as smart as you want. + +To simplify things, we can model variables as a fake type of reference: *owned* +references. Owned references have much the same semantics as mutable references: +they can be re-borrowed in a mutable or shared manner, which makes them no +longer live. Live owned references have the unique property that they can be +moved out of (though mutable references *can* be swapped out of). This power is +only given to *live* owned references because moving its referent would of +course invalidate all outstanding references prematurely. + +As a local lint against inappropriate mutation, only variables that are marked +as `mut` can be borrowed mutably. + +It is interesting to note that Box behaves exactly like an owned reference. It +can be moved out of, and Rust understands it sufficiently to reason about its +paths like a normal variable. + + + + +# Aliasing + +With liveness and paths defined, we can now properly define *aliasing*: + +**A mutable reference is aliased if there exists another live reference to one +of its ancestors or descendants.** + +(If you prefer, you may also say the two live references alias *each other*. +This has no semantic consequences, but is probably a more useful notion when +verifying the soundness of a construct.) + +That's it. Super simple right? Except for the fact that it took us two pages to +define all of the terms in that definition. You know: Super. Simple. + +Actually it's a bit more complicated than that. In addition to references, Rust +has *raw pointers*: `*const T` and `*mut T`. Raw pointers have no inherent +ownership or aliasing semantics. As a result, Rust makes absolutely no effort to +track that they are used correctly, and they are wildly unsafe. + +**It is an open question to what degree raw pointers have alias semantics. +However it is important for these definitions to be sound that the existence of +a raw pointer does not imply some kind of live path.** diff --git a/src/doc/nomicon/repr-rust.md b/src/doc/nomicon/repr-rust.md new file mode 100644 index 0000000000..c8a372be76 --- /dev/null +++ b/src/doc/nomicon/repr-rust.md @@ -0,0 +1,152 @@ +% repr(Rust) + +First and foremost, all types have an alignment specified in bytes. The +alignment of a type specifies what addresses are valid to store the value at. A +value of alignment `n` must only be stored at an address that is a multiple of +`n`. So alignment 2 means you must be stored at an even address, and 1 means +that you can be stored anywhere. Alignment is at least 1, and always a power of +2. Most primitives are generally aligned to their size, although this is +platform-specific behaviour. In particular, on x86 `u64` and `f64` may be only +aligned to 32 bits. + +A type's size must always be a multiple of its alignment. This ensures that an +array of that type may always be indexed by offsetting by a multiple of its +size. Note that the size and alignment of a type may not be known +statically in the case of [dynamically sized types][dst]. + +Rust gives you the following ways to lay out composite data: + +* structs (named product types) +* tuples (anonymous product types) +* arrays (homogeneous product types) +* enums (named sum types -- tagged unions) + +An enum is said to be *C-like* if none of its variants have associated data. + +Composite structures will have an alignment equal to the maximum +of their fields' alignment. Rust will consequently insert padding where +necessary to ensure that all fields are properly aligned and that the overall +type's size is a multiple of its alignment. For instance: + +```rust +struct A { + a: u8, + b: u32, + c: u16, +} +``` + +will be 32-bit aligned assuming these primitives are aligned to their size. +It will therefore have a size that is a multiple of 32-bits. It will potentially +*really* become: + +```rust +struct A { + a: u8, + _pad1: [u8; 3], // to align `b` + b: u32, + c: u16, + _pad2: [u8; 2], // to make overall size multiple of 4 +} +``` + +There is *no indirection* for these types; all data is stored contiguously as +you would expect in C. However with the exception of arrays (which are densely +packed and in-order), the layout of data is not by default specified in Rust. +Given the two following struct definitions: + +```rust +struct A { + a: i32, + b: u64, +} + +struct B { + x: i32, + b: u64, +} +``` + +Rust *does* guarantee that two instances of A have their data laid out in +exactly the same way. However Rust *does not* guarantee that an instance of A +has the same field ordering or padding as an instance of B (in practice there's +no particular reason why they wouldn't, other than that its not currently +guaranteed). + +With A and B as written, this is basically nonsensical, but several other +features of Rust make it desirable for the language to play with data layout in +complex ways. + +For instance, consider this struct: + +```rust +struct Foo { + count: u16, + data1: T, + data2: U, +} +``` + +Now consider the monomorphizations of `Foo` and `Foo`. If +Rust lays out the fields in the order specified, we expect it to pad the +values in the struct to satisfy their alignment requirements. So if Rust +didn't reorder fields, we would expect it to produce the following: + +```rust,ignore +struct Foo { + count: u16, + data1: u16, + data2: u32, +} + +struct Foo { + count: u16, + _pad1: u16, + data1: u32, + data2: u16, + _pad2: u16, +} +``` + +The latter case quite simply wastes space. An optimal use of space therefore +requires different monomorphizations to have *different field orderings*. + +**Note: this is a hypothetical optimization that is not yet implemented in Rust +1.0** + +Enums make this consideration even more complicated. Naively, an enum such as: + +```rust +enum Foo { + A(u32), + B(u64), + C(u8), +} +``` + +would be laid out as: + +```rust +struct FooRepr { + data: u64, // this is either a u64, u32, or u8 based on `tag` + tag: u8, // 0 = A, 1 = B, 2 = C +} +``` + +And indeed this is approximately how it would be laid out in general +(modulo the size and position of `tag`). However there are several cases where +such a representation is inefficient. The classic case of this is Rust's +"null pointer optimization". Given a pointer that is known to not be null +(e.g. `&u32`), an enum can *store* a discriminant bit *inside* the pointer +by using null as a special value. The net result is that +`size_of::>() == size_of::<&T>()` + +There are many types in Rust that are, or contain, "not null" pointers such as +`Box`, `Vec`, `String`, `&T`, and `&mut T`. Similarly, one can imagine +nested enums pooling their tags into a single discriminant, as they are by +definition known to have a limited range of valid values. In principle enums can +use fairly elaborate algorithms to cache bits throughout nested types with +special constrained representations. As such it is *especially* desirable that +we leave enum layout unspecified today. + +[dst]: exotic-sizes.html#dynamically-sized-types-(dsts) diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md new file mode 100644 index 0000000000..2f15b7050e --- /dev/null +++ b/src/doc/nomicon/safe-unsafe-meaning.md @@ -0,0 +1,150 @@ +% How Safe and Unsafe Interact + +So what's the relationship between Safe and Unsafe Rust? How do they interact? + +Rust models the separation between Safe and Unsafe Rust with the `unsafe` +keyword, which can be thought as a sort of *foreign function interface* (FFI) +between Safe and Unsafe Rust. This is the magic behind why we can say Safe Rust +is a safe language: all the scary unsafe bits are relegated exclusively to FFI +*just like every other safe language*. + +However because one language is a subset of the other, the two can be cleanly +intermixed as long as the boundary between Safe and Unsafe Rust is denoted with +the `unsafe` keyword. No need to write headers, initialize runtimes, or any of +that other FFI boiler-plate. + +There are several places `unsafe` can appear in Rust today, which can largely be +grouped into two categories: + +* There are unchecked contracts here. To declare you understand this, I require +you to write `unsafe` elsewhere: + * On functions, `unsafe` is declaring the function to be unsafe to call. + Users of the function must check the documentation to determine what this + means, and then have to write `unsafe` somewhere to identify that they're + aware of the danger. + * On trait declarations, `unsafe` is declaring that *implementing* the trait + is an unsafe operation, as it has contracts that other unsafe code is free + to trust blindly. (More on this below.) + +* I am declaring that I have, to the best of my knowledge, adhered to the +unchecked contracts: + * On trait implementations, `unsafe` is declaring that the contract of the + `unsafe` trait has been upheld. + * On blocks, `unsafe` is declaring any unsafety from an unsafe + operation within to be handled, and therefore the parent function is safe. + +There is also `#[unsafe_no_drop_flag]`, which is a special case that exists for +historical reasons and is in the process of being phased out. See the section on +[drop flags][] for details. + +Some examples of unsafe functions: + +* `slice::get_unchecked` will perform unchecked indexing, allowing memory + safety to be freely violated. +* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is + not "in bounds" as defined by LLVM. +* `mem::transmute` reinterprets some value as having the given type, + bypassing type safety in arbitrary ways. (see [conversions][] for details) +* All FFI functions are `unsafe` because they can do arbitrary things. + C being an obvious culprit, but generally any language can do something + that Rust isn't happy about. + +As of Rust 1.0 there are exactly two unsafe traits: + +* `Send` is a marker trait (it has no actual API) that promises implementors + are safe to send (move) to another thread. +* `Sync` is a marker trait that promises that threads can safely share + implementors through a shared reference. + +The need for unsafe traits boils down to the fundamental property of safe code: + +**No matter how completely awful Safe code is, it can't cause Undefined +Behaviour.** + +This means that Unsafe Rust, **the royal vanguard of Undefined Behaviour**, has to be +*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust +specific safe code. Anything else would degenerate into infinite spirals of +paranoid despair. In particular it's generally regarded as ok to trust the standard library +to be correct. `std` is effectively an extension of the language, and you +really just have to trust the language. If `std` fails to uphold the +guarantees it declares, then it's basically a language bug. + +That said, it would be best to minimize *needlessly* relying on properties of +concrete safe code. Bugs happen! Of course, I must reinforce that this is only +a concern for Unsafe code. Safe code can blindly trust anyone and everyone +as far as basic memory-safety is concerned. + +On the other hand, safe traits are free to declare arbitrary contracts, but because +implementing them is safe, unsafe code can't trust those contracts to actually +be upheld. This is different from the concrete case because *anyone* can +randomly implement the interface. There is something fundamentally different +about trusting a particular piece of code to be correct, and trusting *all the +code that will ever be written* to be correct. + +For instance Rust has `PartialOrd` and `Ord` traits to try to differentiate +between types which can "just" be compared, and those that actually implement a +total ordering. Pretty much every API that wants to work with data that can be +compared wants Ord data. For instance, a sorted map like BTreeMap +*doesn't even make sense* for partially ordered types. If you claim to implement +Ord for a type, but don't actually provide a proper total ordering, BTreeMap will +get *really confused* and start making a total mess of itself. Data that is +inserted may be impossible to find! + +But that's okay. BTreeMap is safe, so it guarantees that even if you give it a +completely garbage Ord implementation, it will still do something *safe*. You +won't start reading uninitialized or unallocated memory. In fact, BTreeMap +manages to not actually lose any of your data. When the map is dropped, all the +destructors will be successfully called! Hooray! + +However BTreeMap is implemented using a modest spoonful of Unsafe Rust (most collections +are). That means that it's not necessarily *trivially true* that a bad Ord +implementation will make BTreeMap behave safely. BTreeMap must be sure not to rely +on Ord *where safety is at stake*. Ord is provided by safe code, and safety is not +safe code's responsibility to uphold. + +But wouldn't it be grand if there was some way for Unsafe to trust some trait +contracts *somewhere*? This is the problem that unsafe traits tackle: by marking +*the trait itself* as unsafe to implement, unsafe code can trust the implementation +to uphold the trait's contract. Although the trait implementation may be +incorrect in arbitrary other ways. + +For instance, given a hypothetical UnsafeOrd trait, this is technically a valid +implementation: + +```rust +# use std::cmp::Ordering; +# struct MyType; +# unsafe trait UnsafeOrd { fn cmp(&self, other: &Self) -> Ordering; } +unsafe impl UnsafeOrd for MyType { + fn cmp(&self, other: &Self) -> Ordering { + Ordering::Equal + } +} +``` + +But it's probably not the implementation you want. + +Rust has traditionally avoided making traits unsafe because it makes Unsafe +pervasive, which is not desirable. Send and Sync are unsafe is because thread +safety is a *fundamental property* that unsafe code cannot possibly hope to defend +against in the same way it would defend against a bad Ord implementation. The +only way to possibly defend against thread-unsafety would be to *not use +threading at all*. Making every load and store atomic isn't even sufficient, +because it's possible for complex invariants to exist between disjoint locations +in memory. For instance, the pointer and capacity of a Vec must be in sync. + +Even concurrent paradigms that are traditionally regarded as Totally Safe like +message passing implicitly rely on some notion of thread safety -- are you +really message-passing if you pass a pointer? Send and Sync therefore require +some fundamental level of trust that Safe code can't provide, so they must be +unsafe to implement. To help obviate the pervasive unsafety that this would +introduce, Send (resp. Sync) is automatically derived for all types composed only +of Send (resp. Sync) values. 99% of types are Send and Sync, and 99% of those +never actually say it (the remaining 1% is overwhelmingly synchronization +primitives). + + + + +[drop flags]: drop-flags.html +[conversions]: conversions.html diff --git a/src/doc/nomicon/send-and-sync.md b/src/doc/nomicon/send-and-sync.md new file mode 100644 index 0000000000..334d5c9dd5 --- /dev/null +++ b/src/doc/nomicon/send-and-sync.md @@ -0,0 +1,80 @@ +% Send and Sync + +Not everything obeys inherited mutability, though. Some types allow you to +multiply alias a location in memory while mutating it. Unless these types use +synchronization to manage this access, they are absolutely not thread safe. Rust +captures this with through the `Send` and `Sync` traits. + +* A type is Send if it is safe to send it to another thread. +* A type is Sync if it is safe to share between threads (`&T` is Send). + +Send and Sync are fundamental to Rust's concurrency story. As such, a +substantial amount of special tooling exists to make them work right. First and +foremost, they're [unsafe traits][]. This means that they are unsafe to +implement, and other unsafe code can that they are correctly +implemented. Since they're *marker traits* (they have no associated items like +methods), correctly implemented simply means that they have the intrinsic +properties an implementor should have. Incorrectly implementing Send or Sync can +cause Undefined Behaviour. + +Send and Sync are also automatically derived traits. This means that, unlike +every other trait, if a type is composed entirely of Send or Sync types, then it +is Send or Sync. Almost all primitives are Send and Sync, and as a consequence +pretty much all types you'll ever interact with are Send and Sync. + +Major exceptions include: + +* raw pointers are neither Send nor Sync (because they have no safety guards). +* `UnsafeCell` isn't Sync (and therefore `Cell` and `RefCell` aren't). +* `Rc` isn't Send or Sync (because the refcount is shared and unsynchronized). + +`Rc` and `UnsafeCell` are very fundamentally not thread-safe: they enable +unsynchronized shared mutable state. However raw pointers are, strictly +speaking, marked as thread-unsafe as more of a *lint*. Doing anything useful +with a raw pointer requires dereferencing it, which is already unsafe. In that +sense, one could argue that it would be "fine" for them to be marked as thread +safe. + +However it's important that they aren't thread safe to prevent types that +contain them from being automatically marked as thread safe. These types have +non-trivial untracked ownership, and it's unlikely that their author was +necessarily thinking hard about thread safety. In the case of Rc, we have a nice +example of a type that contains a `*mut` that is definitely not thread safe. + +Types that aren't automatically derived can simply implement them if desired: + +```rust +struct MyBox(*mut u8); + +unsafe impl Send for MyBox {} +unsafe impl Sync for MyBox {} +``` + +In the *incredibly rare* case that a type is inappropriately automatically +derived to be Send or Sync, then one can also unimplement Send and Sync: + +```rust +#![feature(optin_builtin_traits)] + +// I have some magic semantics for some synchronization primitive! +struct SpecialThreadToken(u8); + +impl !Send for SpecialThreadToken {} +impl !Sync for SpecialThreadToken {} +``` + +Note that *in and of itself* it is impossible to incorrectly derive Send and +Sync. Only types that are ascribed special meaning by other unsafe code can +possible cause trouble by being incorrectly Send or Sync. + +Most uses of raw pointers should be encapsulated behind a sufficient abstraction +that Send and Sync can be derived. For instance all of Rust's standard +collections are Send and Sync (when they contain Send and Sync types) in spite +of their pervasive use of raw pointers to manage allocations and complex ownership. +Similarly, most iterators into these collections are Send and Sync because they +largely behave like an `&` or `&mut` into the collection. + +TODO: better explain what can or can't be Send or Sync. Sufficient to appeal +only to data races? + +[unsafe traits]: safe-unsafe-meaning.html diff --git a/src/doc/nomicon/subtyping.md b/src/doc/nomicon/subtyping.md new file mode 100644 index 0000000000..3c57297f32 --- /dev/null +++ b/src/doc/nomicon/subtyping.md @@ -0,0 +1,212 @@ +% Subtyping and Variance + +Although Rust doesn't have any notion of structural inheritance, it *does* +include subtyping. In Rust, subtyping derives entirely from lifetimes. Since +lifetimes are scopes, we can partially order them based on the *contains* +(outlives) relationship. We can even express this as a generic bound. + +Subtyping on lifetimes is in terms of that relationship: if `'a: 'b` ("a contains +b" or "a outlives b"), then `'a` is a subtype of `'b`. This is a large source of +confusion, because it seems intuitively backwards to many: the bigger scope is a +*subtype* of the smaller scope. + +This does in fact make sense, though. The intuitive reason for this is that if +you expect an `&'a u8`, then it's totally fine for me to hand you an `&'static +u8`, in the same way that if you expect an Animal in Java, it's totally fine for +me to hand you a Cat. Cats are just Animals *and more*, just as `'static` is +just `'a` *and more*. + +(Note, the subtyping relationship and typed-ness of lifetimes is a fairly +arbitrary construct that some disagree with. However it simplifies our analysis +to treat lifetimes and types uniformly.) + +Higher-ranked lifetimes are also subtypes of every concrete lifetime. This is +because taking an arbitrary lifetime is strictly more general than taking a +specific one. + + + +# Variance + +Variance is where things get a bit complicated. + +Variance is a property that *type constructors* have with respect to their +arguments. A type constructor in Rust is a generic type with unbound arguments. +For instance `Vec` is a type constructor that takes a `T` and returns a +`Vec`. `&` and `&mut` are type constructors that take two inputs: a +lifetime, and a type to point to. + +A type constructor's *variance* is how the subtyping of its inputs affects the +subtyping of its outputs. There are two kinds of variance in Rust: + +* F is *variant* over `T` if `T` being a subtype of `U` implies + `F` is a subtype of `F` (subtyping "passes through") +* F is *invariant* over `T` otherwise (no subtyping relation can be derived) + +(For those of you who are familiar with variance from other languages, what we +refer to as "just" variance is in fact *covariance*. Rust does not have +contravariance. Historically Rust did have some contravariance but it was +scrapped due to poor interactions with other features. If you experience +contravariance in Rust call your local compiler developer for medical advice.) + +Some important variances: + +* `&'a T` is variant over `'a` and `T` (as is `*const T` by metaphor) +* `&'a mut T` is variant with over `'a` but invariant over `T` +* `Fn(T) -> U` is invariant over `T`, but variant over `U` +* `Box`, `Vec`, and all other collections are variant over the types of + their contents +* `UnsafeCell`, `Cell`, `RefCell`, `Mutex` and all other + interior mutability types are invariant over T (as is `*mut T` by metaphor) + +To understand why these variances are correct and desirable, we will consider +several examples. + + +We have already covered why `&'a T` should be variant over `'a` when +introducing subtyping: it's desirable to be able to pass longer-lived things +where shorter-lived things are needed. + +Similar reasoning applies to why it should be variant over T. It is reasonable +to be able to pass `&&'static str` where an `&&'a str` is expected. The +additional level of indirection does not change the desire to be able to pass +longer lived things where shorted lived things are expected. + +However this logic doesn't apply to `&mut`. To see why `&mut` should +be invariant over T, consider the following code: + +```rust,ignore +fn overwrite(input: &mut T, new: &mut T) { + *input = *new; +} + +fn main() { + let mut forever_str: &'static str = "hello"; + { + let string = String::from("world"); + overwrite(&mut forever_str, &mut &*string); + } + // Oops, printing free'd memory + println!("{}", forever_str); +} +``` + +The signature of `overwrite` is clearly valid: it takes mutable references to +two values of the same type, and overwrites one with the other. If `&mut T` was +variant over T, then `&mut &'a str` would be a subtype of `&mut &'static str`, +since `&'a str` is a subtype of `&'static str`. Therefore the lifetime of +`forever_str` would successfully be "shrunk" down to the shorter lifetime of +`string`, and `overwrite` would be called successfully. `string` would +subsequently be dropped, and `forever_str` would point to freed memory when we +print it! Therefore `&mut` should be invariant. + +This is the general theme of variance vs invariance: if variance would allow you +to store a short-lived value into a longer-lived slot, then you must be +invariant. + +However it *is* sound for `&'a mut T` to be variant over `'a`. The key difference +between `'a` and T is that `'a` is a property of the reference itself, +while T is something the reference is borrowing. If you change T's type, then +the source still remembers the original type. However if you change the +lifetime's type, no one but the reference knows this information, so it's fine. +Put another way: `&'a mut T` owns `'a`, but only *borrows* T. + +`Box` and `Vec` are interesting cases because they're variant, but you can +definitely store values in them! This is where Rust gets really clever: it's +fine for them to be variant because you can only store values +in them *via a mutable reference*! The mutable reference makes the whole type +invariant, and therefore prevents you from smuggling a short-lived type into +them. + +Being variant allows `Box` and `Vec` to be weakened when shared +immutably. So you can pass a `&Box<&'static str>` where a `&Box<&'a str>` is +expected. + +However what should happen when passing *by-value* is less obvious. It turns out +that, yes, you can use subtyping when passing by-value. That is, this works: + +```rust +fn get_box<'a>(str: &'a str) -> Box<&'a str> { + // string literals are `&'static str`s + Box::new("hello") +} +``` + +Weakening when you pass by-value is fine because there's no one else who +"remembers" the old lifetime in the Box. The reason a variant `&mut` was +trouble was because there's always someone else who remembers the original +subtype: the actual owner. + +The invariance of the cell types can be seen as follows: `&` is like an `&mut` +for a cell, because you can still store values in them through an `&`. Therefore +cells must be invariant to avoid lifetime smuggling. + +`Fn` is the most subtle case because it has mixed variance. To see why +`Fn(T) -> U` should be invariant over T, consider the following function +signature: + +```rust,ignore +// 'a is derived from some parent scope +fn foo(&'a str) -> usize; +``` + +This signature claims that it can handle any `&str` that lives at least as +long as `'a`. Now if this signature was variant over `&'a str`, that +would mean + +```rust,ignore +fn foo(&'static str) -> usize; +``` + +could be provided in its place, as it would be a subtype. However this function +has a stronger requirement: it says that it can only handle `&'static str`s, +and nothing else. Giving `&'a str`s to it would be unsound, as it's free to +assume that what it's given lives forever. Therefore functions are not variant +over their arguments. + +To see why `Fn(T) -> U` should be variant over U, consider the following +function signature: + +```rust,ignore +// 'a is derived from some parent scope +fn foo(usize) -> &'a str; +``` + +This signature claims that it will return something that outlives `'a`. It is +therefore completely reasonable to provide + +```rust,ignore +fn foo(usize) -> &'static str; +``` + +in its place. Therefore functions are variant over their return type. + +`*const` has the exact same semantics as `&`, so variance follows. `*mut` on the +other hand can dereference to an `&mut` whether shared or not, so it is marked +as invariant just like cells. + +This is all well and good for the types the standard library provides, but +how is variance determined for type that *you* define? A struct, informally +speaking, inherits the variance of its fields. If a struct `Foo` +has a generic argument `A` that is used in a field `a`, then Foo's variance +over `A` is exactly `a`'s variance. However this is complicated if `A` is used +in multiple fields. + +* If all uses of A are variant, then Foo is variant over A +* Otherwise, Foo is invariant over A + +```rust +use std::cell::Cell; + +struct Foo<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H> { + a: &'a A, // variant over 'a and A + b: &'b mut B, // invariant over 'b and B + c: *const C, // variant over C + d: *mut D, // invariant over D + e: Vec, // variant over E + f: Cell, // invariant over F + g: G, // variant over G + h1: H, // would also be variant over H except... + h2: Cell, // invariant over H, because invariance wins +} +``` diff --git a/src/doc/nomicon/transmutes.md b/src/doc/nomicon/transmutes.md new file mode 100644 index 0000000000..f19dda0d8b --- /dev/null +++ b/src/doc/nomicon/transmutes.md @@ -0,0 +1,35 @@ +% Transmutes + +Get out of our way type system! We're going to reinterpret these bits or die +trying! Even though this book is all about doing things that are unsafe, I +really can't emphasize that you should deeply think about finding Another Way +than the operations covered in this section. This is really, truly, the most +horribly unsafe thing you can do in Rust. The railguards here are dental floss. + +`mem::transmute` takes a value of type `T` and reinterprets it to have +type `U`. The only restriction is that the `T` and `U` are verified to have the +same size. The ways to cause Undefined Behaviour with this are mind boggling. + +* First and foremost, creating an instance of *any* type with an invalid state + is going to cause arbitrary chaos that can't really be predicted. +* Transmute has an overloaded return type. If you do not specify the return type + it may produce a surprising type to satisfy inference. +* Making a primitive with an invalid value is UB +* Transmuting between non-repr(C) types is UB +* Transmuting an & to &mut is UB + * Transmuting an & to &mut is *always* UB + * No you can't do it + * No you're not special +* Transmuting to a reference without an explicitly provided lifetime + produces an [unbounded lifetime][] + +`mem::transmute_copy` somehow manages to be *even more* wildly unsafe than +this. It copies `size_of` bytes out of an `&T` and interprets them as a `U`. +The size check that `mem::transmute` has is gone (as it may be valid to copy +out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`. + +Also of course you can get most of the functionality of these functions using +pointer casts. + + +[unbounded lifetime]: unbounded-lifetimes.html diff --git a/src/doc/nomicon/unbounded-lifetimes.md b/src/doc/nomicon/unbounded-lifetimes.md new file mode 100644 index 0000000000..b540ab4ed5 --- /dev/null +++ b/src/doc/nomicon/unbounded-lifetimes.md @@ -0,0 +1,37 @@ +% Unbounded Lifetimes + +Unsafe code can often end up producing references or lifetimes out of thin air. +Such lifetimes come into the world as *unbounded*. The most common source of this +is derefencing a raw pointer, which produces a reference with an unbounded lifetime. +Such a lifetime becomes as big as context demands. This is in fact more powerful +than simply becoming `'static`, because for instance `&'static &'a T` +will fail to typecheck, but the unbound lifetime will perfectly mold into +`&'a &'a T` as needed. However for most intents and purposes, such an unbounded +lifetime can be regarded as `'static`. + +Almost no reference is `'static`, so this is probably wrong. `transmute` and +`transmute_copy` are the two other primary offenders. One should endeavour to +bound an unbounded lifetime as quick as possible, especially across function +boundaries. + +Given a function, any output lifetimes that don't derive from inputs are +unbounded. For instance: + +```rust,ignore +fn get_str<'a>() -> &'a str; +``` + +will produce an `&str` with an unbounded lifetime. The easiest way to avoid +unbounded lifetimes is to use lifetime elision at the function boundary. +If an output lifetime is elided, then it *must* be bounded by an input lifetime. +Of course it might be bounded by the *wrong* lifetime, but this will usually +just cause a compiler error, rather than allow memory safety to be trivially +violated. + +Within a function, bounding lifetimes is more error-prone. The safest and easiest +way to bound a lifetime is to return it from a function with a bound lifetime. +However if this is unacceptable, the reference can be placed in a location with +a specific lifetime. Unfortunately it's impossible to name all lifetimes involved +in a function. To get around this, you can in principle use `copy_lifetime`, though +these are unstable due to their awkward nature and questionable utility. + diff --git a/src/doc/nomicon/unchecked-uninit.md b/src/doc/nomicon/unchecked-uninit.md new file mode 100644 index 0000000000..da9fb294a1 --- /dev/null +++ b/src/doc/nomicon/unchecked-uninit.md @@ -0,0 +1,85 @@ +% Unchecked Uninitialized Memory + +One interesting exception to this rule is working with arrays. Safe Rust doesn't +permit you to partially initialize an array. When you initialize an array, you +can either set every value to the same thing with `let x = [val; N]`, or you can +specify each member individually with `let x = [val1, val2, val3]`. +Unfortunately this is pretty rigid, especially if you need to initialize your +array in a more incremental or dynamic way. + +Unsafe Rust gives us a powerful tool to handle this problem: +`mem::uninitialized`. This function pretends to return a value when really +it does nothing at all. Using it, we can convince Rust that we have initialized +a variable, allowing us to do trickier things with conditional and incremental +initialization. + +Unfortunately, this opens us up to all kinds of problems. Assignment has a +different meaning to Rust based on whether it believes that a variable is +initialized or not. If it's believed uninitialized, then Rust will semantically +just memcopy the bits over the uninitialized ones, and do nothing else. However +if Rust believes a value to be initialized, it will try to `Drop` the old value! +Since we've tricked Rust into believing that the value is initialized, we can no +longer safely use normal assignment. + +This is also a problem if you're working with a raw system allocator, which +returns a pointer to uninitialized memory. + +To handle this, we must use the `ptr` module. In particular, it provides +three functions that allow us to assign bytes to a location in memory without +dropping the old value: `write`, `copy`, and `copy_nonoverlapping`. + +* `ptr::write(ptr, val)` takes a `val` and moves it into the address pointed + to by `ptr`. +* `ptr::copy(src, dest, count)` copies the bits that `count` T's would occupy + from src to dest. (this is equivalent to memmove -- note that the argument + order is reversed!) +* `ptr::copy_nonoverlapping(src, dest, count)` does what `copy` does, but a + little faster on the assumption that the two ranges of memory don't overlap. + (this is equivalent to memcpy -- note that the argument order is reversed!) + +It should go without saying that these functions, if misused, will cause serious +havoc or just straight up Undefined Behaviour. The only things that these +functions *themselves* require is that the locations you want to read and write +are allocated. However the ways writing arbitrary bits to arbitrary +locations of memory can break things are basically uncountable! + +Putting this all together, we get the following: + +```rust +use std::mem; +use std::ptr; + +// size of the array is hard-coded but easy to change. This means we can't +// use [a, b, c] syntax to initialize the array, though! +const SIZE: usize = 10; + +let mut x: [Box; SIZE]; + +unsafe { + // convince Rust that x is Totally Initialized + x = mem::uninitialized(); + for i in 0..SIZE { + // very carefully overwrite each index without reading it + // NOTE: exception safety is not a concern; Box can't panic + ptr::write(&mut x[i], Box::new(i as u32)); + } +} + +println!("{:?}", x); +``` + +It's worth noting that you don't need to worry about `ptr::write`-style +shenanigans with types which don't implement `Drop` or contain `Drop` types, +because Rust knows not to try to drop them. Similarly you should be able to +assign to fields of partially initialized structs directly if those fields don't +contain any `Drop` types. + +However when working with uninitialized memory you need to be ever-vigilant for +Rust trying to drop values you make like this before they're fully initialized. +Every control path through that variable's scope must initialize the value +before it ends, if has a destructor. +*[This includes code panicking](unwinding.html)*. + +And that's about it for working with uninitialized memory! Basically nothing +anywhere expects to be handed uninitialized memory, so if you're going to pass +it around at all, be sure to be *really* careful. diff --git a/src/doc/nomicon/uninitialized.md b/src/doc/nomicon/uninitialized.md new file mode 100644 index 0000000000..915ea86029 --- /dev/null +++ b/src/doc/nomicon/uninitialized.md @@ -0,0 +1,10 @@ +% Working With Uninitialized Memory + +All runtime-allocated memory in a Rust program begins its life as +*uninitialized*. In this state the value of the memory is an indeterminate pile +of bits that may or may not even reflect a valid state for the type that is +supposed to inhabit that location of memory. Attempting to interpret this memory +as a value of *any* type will cause Undefined Behaviour. Do Not Do This. + +Rust provides mechanisms to work with uninitialized memory in checked (safe) and +unchecked (unsafe) ways. \ No newline at end of file diff --git a/src/doc/nomicon/unwinding.md b/src/doc/nomicon/unwinding.md new file mode 100644 index 0000000000..3ad95dde39 --- /dev/null +++ b/src/doc/nomicon/unwinding.md @@ -0,0 +1,49 @@ +% Unwinding + +Rust has a *tiered* error-handling scheme: + +* If something might reasonably be absent, Option is used. +* If something goes wrong and can reasonably be handled, Result is used. +* If something goes wrong and cannot reasonably be handled, the thread panics. +* If something catastrophic happens, the program aborts. + +Option and Result are overwhelmingly preferred in most situations, especially +since they can be promoted into a panic or abort at the API user's discretion. +Panics cause the thread to halt normal execution and unwind its stack, calling +destructors as if every function instantly returned. + +As of 1.0, Rust is of two minds when it comes to panics. In the long-long-ago, +Rust was much more like Erlang. Like Erlang, Rust had lightweight tasks, +and tasks were intended to kill themselves with a panic when they reached an +untenable state. Unlike an exception in Java or C++, a panic could not be +caught at any time. Panics could only be caught by the owner of the task, at which +point they had to be handled or *that* task would itself panic. + +Unwinding was important to this story because if a task's +destructors weren't called, it would cause memory and other system resources to +leak. Since tasks were expected to die during normal execution, this would make +Rust very poor for long-running systems! + +As the Rust we know today came to be, this style of programming grew out of +fashion in the push for less-and-less abstraction. Light-weight tasks were +killed in the name of heavy-weight OS threads. Still, on stable Rust as of 1.0 +panics can only be caught by the parent thread. This means catching a panic +requires spinning up an entire OS thread! This unfortunately stands in conflict +to Rust's philosophy of zero-cost abstractions. + +There is an unstable API called `catch_panic` that enables catching a panic +without spawning a thread. Still, we would encourage you to only do this +sparingly. In particular, Rust's current unwinding implementation is heavily +optimized for the "doesn't unwind" case. If a program doesn't unwind, there +should be no runtime cost for the program being *ready* to unwind. As a +consequence, actually unwinding will be more expensive than in e.g. Java. +Don't build your programs to unwind under normal circumstances. Ideally, you +should only panic for programming errors or *extreme* problems. + +Rust's unwinding strategy is not specified to be fundamentally compatible +with any other language's unwinding. As such, unwinding into Rust from another +language, or unwinding into another language from Rust is Undefined Behaviour. +You must *absolutely* catch any panics at the FFI boundary! What you do at that +point is up to you, but *something* must be done. If you fail to do this, +at best, your application will crash and burn. At worst, your application *won't* +crash and burn, and will proceed with completely clobbered state. diff --git a/src/doc/nomicon/vec-alloc.md b/src/doc/nomicon/vec-alloc.md new file mode 100644 index 0000000000..fc7feba235 --- /dev/null +++ b/src/doc/nomicon/vec-alloc.md @@ -0,0 +1,222 @@ +% Allocating Memory + +Using Unique throws a wrench in an important feature of Vec (and indeed all of +the std collections): an empty Vec doesn't actually allocate at all. So if we +can't allocate, but also can't put a null pointer in `ptr`, what do we do in +`Vec::new`? Well, we just put some other garbage in there! + +This is perfectly fine because we already have `cap == 0` as our sentinel for no +allocation. We don't even need to handle it specially in almost any code because +we usually need to check if `cap > len` or `len > 0` anyway. The traditional +Rust value to put here is `0x01`. The standard library actually exposes this +as `std::rt::heap::EMPTY`. There are quite a few places where we'll +want to use `heap::EMPTY` because there's no real allocation to talk about but +`null` would make the compiler do bad things. + +All of the `heap` API is totally unstable under the `heap_api` feature, though. +We could trivially define `heap::EMPTY` ourselves, but we'll want the rest of +the `heap` API anyway, so let's just get that dependency over with. + +So: + +```rust,ignore +#![feature(heap_api)] + +use std::rt::heap::EMPTY; +use std::mem; + +impl Vec { + fn new() -> Self { + assert!(mem::size_of::() != 0, "We're not ready to handle ZSTs"); + unsafe { + // need to cast EMPTY to the actual ptr type we want, let + // inference handle it. + Vec { ptr: Unique::new(heap::EMPTY as *mut _), len: 0, cap: 0 } + } + } +} +``` + +I slipped in that assert there because zero-sized types will require some +special handling throughout our code, and I want to defer the issue for now. +Without this assert, some of our early drafts will do some Very Bad Things. + +Next we need to figure out what to actually do when we *do* want space. For +that, we'll need to use the rest of the heap APIs. These basically allow us to +talk directly to Rust's allocator (jemalloc by default). + +We'll also need a way to handle out-of-memory (OOM) conditions. The standard +library calls the `abort` intrinsic, which just calls an illegal instruction to +crash the whole program. The reason we abort and don't panic is because +unwinding can cause allocations to happen, and that seems like a bad thing to do +when your allocator just came back with "hey I don't have any more memory". + +Of course, this is a bit silly since most platforms don't actually run out of +memory in a conventional way. Your operating system will probably kill the +application by another means if you legitimately start using up all the memory. +The most likely way we'll trigger OOM is by just asking for ludicrous quantities +of memory at once (e.g. half the theoretical address space). As such it's +*probably* fine to panic and nothing bad will happen. Still, we're trying to be +like the standard library as much as possible, so we'll just kill the whole +program. + +We said we don't want to use intrinsics, so doing exactly what `std` does is +out. Instead, we'll call `std::process::exit` with some random number. + +```rust +fn oom() { + ::std::process::exit(-9999); +} +``` + +Okay, now we can write growing. Roughly, we want to have this logic: + +```text +if cap == 0: + allocate() + cap = 1 +else: + reallocate() + cap *= 2 +``` + +But Rust's only supported allocator API is so low level that we'll need to do a +fair bit of extra work. We also need to guard against some special +conditions that can occur with really large allocations or empty allocations. + +In particular, `ptr::offset` will cause us a lot of trouble, because it has +the semantics of LLVM's GEP inbounds instruction. If you're fortunate enough to +not have dealt with this instruction, here's the basic story with GEP: alias +analysis, alias analysis, alias analysis. It's super important to an optimizing +compiler to be able to reason about data dependencies and aliasing. + +As a simple example, consider the following fragment of code: + +```rust +# let x = &mut 0; +# let y = &mut 0; +*x *= 7; +*y *= 3; +``` + +If the compiler can prove that `x` and `y` point to different locations in +memory, the two operations can in theory be executed in parallel (by e.g. +loading them into different registers and working on them independently). +However the compiler can't do this in general because if x and y point to +the same location in memory, the operations need to be done to the same value, +and they can't just be merged afterwards. + +When you use GEP inbounds, you are specifically telling LLVM that the offsets +you're about to do are within the bounds of a single "allocated" entity. The +ultimate payoff being that LLVM can assume that if two pointers are known to +point to two disjoint objects, all the offsets of those pointers are *also* +known to not alias (because you won't just end up in some random place in +memory). LLVM is heavily optimized to work with GEP offsets, and inbounds +offsets are the best of all, so it's important that we use them as much as +possible. + +So that's what GEP's about, how can it cause us trouble? + +The first problem is that we index into arrays with unsigned integers, but +GEP (and as a consequence `ptr::offset`) takes a signed integer. This means +that half of the seemingly valid indices into an array will overflow GEP and +actually go in the wrong direction! As such we must limit all allocations to +`isize::MAX` elements. This actually means we only need to worry about +byte-sized objects, because e.g. `> isize::MAX` `u16`s will truly exhaust all of +the system's memory. However in order to avoid subtle corner cases where someone +reinterprets some array of `< isize::MAX` objects as bytes, std limits all +allocations to `isize::MAX` bytes. + +On all 64-bit targets that Rust currently supports we're artificially limited +to significantly less than all 64 bits of the address space (modern x64 +platforms only expose 48-bit addressing), so we can rely on just running out of +memory first. However on 32-bit targets, particularly those with extensions to +use more of the address space (PAE x86 or x32), it's theoretically possible to +successfully allocate more than `isize::MAX` bytes of memory. + +However since this is a tutorial, we're not going to be particularly optimal +here, and just unconditionally check, rather than use clever platform-specific +`cfg`s. + +The other corner-case we need to worry about is empty allocations. There will +be two kinds of empty allocations we need to worry about: `cap = 0` for all T, +and `cap > 0` for zero-sized types. + +These cases are tricky because they come +down to what LLVM means by "allocated". LLVM's notion of an +allocation is significantly more abstract than how we usually use it. Because +LLVM needs to work with different languages' semantics and custom allocators, +it can't really intimately understand allocation. Instead, the main idea behind +allocation is "doesn't overlap with other stuff". That is, heap allocations, +stack allocations, and globals don't randomly overlap. Yep, it's about alias +analysis. As such, Rust can technically play a bit fast an loose with the notion of +an allocation as long as it's *consistent*. + +Getting back to the empty allocation case, there are a couple of places where +we want to offset by 0 as a consequence of generic code. The question is then: +is it consistent to do so? For zero-sized types, we have concluded that it is +indeed consistent to do a GEP inbounds offset by an arbitrary number of +elements. This is a runtime no-op because every element takes up no space, +and it's fine to pretend that there's infinite zero-sized types allocated +at `0x01`. No allocator will ever allocate that address, because they won't +allocate `0x00` and they generally allocate to some minimal alignment higher +than a byte. Also generally the whole first page of memory is +protected from being allocated anyway (a whole 4k, on many platforms). + +However what about for positive-sized types? That one's a bit trickier. In +principle, you can argue that offsetting by 0 gives LLVM no information: either +there's an element before the address or after it, but it can't know which. +However we've chosen to conservatively assume that it may do bad things. As +such we will guard against this case explicitly. + +*Phew* + +Ok with all the nonsense out of the way, let's actually allocate some memory: + +```rust,ignore +fn grow(&mut self) { + // this is all pretty delicate, so let's say it's all unsafe + unsafe { + // current API requires us to specify size and alignment manually. + let align = mem::align_of::(); + let elem_size = mem::size_of::(); + + let (new_cap, ptr) = if self.cap == 0 { + let ptr = heap::allocate(elem_size, align); + (1, ptr) + } else { + // as an invariant, we can assume that `self.cap < isize::MAX`, + // so this doesn't need to be checked. + let new_cap = self.cap * 2; + // Similarly this can't overflow due to previously allocating this + let old_num_bytes = self.cap * elem_size; + + // check that the new allocation doesn't exceed `isize::MAX` at all + // regardless of the actual size of the capacity. This combines the + // `new_cap <= isize::MAX` and `new_num_bytes <= usize::MAX` checks + // we need to make. We lose the ability to allocate e.g. 2/3rds of + // the address space with a single Vec of i16's on 32-bit though. + // Alas, poor Yorick -- I knew him, Horatio. + assert!(old_num_bytes <= (::std::isize::MAX as usize) / 2, + "capacity overflow"); + + let new_num_bytes = old_num_bytes * 2; + let ptr = heap::reallocate(*self.ptr as *mut _, + old_num_bytes, + new_num_bytes, + align); + (new_cap, ptr) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom(); } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } +} +``` + +Nothing particularly tricky here. Just computing sizes and alignments and doing +some careful multiplication checks. + diff --git a/src/doc/nomicon/vec-dealloc.md b/src/doc/nomicon/vec-dealloc.md new file mode 100644 index 0000000000..b767caa491 --- /dev/null +++ b/src/doc/nomicon/vec-dealloc.md @@ -0,0 +1,29 @@ +% Deallocating + +Next we should implement Drop so that we don't massively leak tons of resources. +The easiest way is to just call `pop` until it yields None, and then deallocate +our buffer. Note that calling `pop` is unneeded if `T: !Drop`. In theory we can +ask Rust if `T` `needs_drop` and omit the calls to `pop`. However in practice +LLVM is *really* good at removing simple side-effect free code like this, so I +wouldn't bother unless you notice it's not being stripped (in this case it is). + +We must not call `heap::deallocate` when `self.cap == 0`, as in this case we +haven't actually allocated any memory. + + +```rust,ignore +impl Drop for Vec { + fn drop(&mut self) { + if self.cap != 0 { + while let Some(_) = self.pop() { } + + let align = mem::align_of::(); + let elem_size = mem::size_of::(); + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.ptr, num_bytes, align); + } + } + } +} +``` diff --git a/src/doc/nomicon/vec-deref.md b/src/doc/nomicon/vec-deref.md new file mode 100644 index 0000000000..6460eab479 --- /dev/null +++ b/src/doc/nomicon/vec-deref.md @@ -0,0 +1,42 @@ +% Deref + +Alright! We've got a decent minimal stack implemented. We can push, we can +pop, and we can clean up after ourselves. However there's a whole mess of +functionality we'd reasonably want. In particular, we have a proper array, but +none of the slice functionality. That's actually pretty easy to solve: we can +implement `Deref`. This will magically make our Vec coerce to, and +behave like, a slice in all sorts of conditions. + +All we need is `slice::from_raw_parts`. It will correctly handle empty slices +for us. Later once we set up zero-sized type support it will also Just Work +for those too. + +```rust,ignore +use std::ops::Deref; + +impl Deref for Vec { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { + ::std::slice::from_raw_parts(*self.ptr, self.len) + } + } +} +``` + +And let's do DerefMut too: + +```rust,ignore +use std::ops::DerefMut; + +impl DerefMut for Vec { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { + ::std::slice::from_raw_parts_mut(*self.ptr, self.len) + } + } +} +``` + +Now we have `len`, `first`, `last`, indexing, slicing, sorting, `iter`, +`iter_mut`, and all other sorts of bells and whistles provided by slice. Sweet! diff --git a/src/doc/nomicon/vec-drain.md b/src/doc/nomicon/vec-drain.md new file mode 100644 index 0000000000..4521bbdd05 --- /dev/null +++ b/src/doc/nomicon/vec-drain.md @@ -0,0 +1,150 @@ +% Drain + +Let's move on to Drain. Drain is largely the same as IntoIter, except that +instead of consuming the Vec, it borrows the Vec and leaves its allocation +untouched. For now we'll only implement the "basic" full-range version. + +```rust,ignore +use std::marker::PhantomData; + +struct Drain<'a, T: 'a> { + // Need to bound the lifetime here, so we do it with `&'a mut Vec` + // because that's semantically what we contain. We're "just" calling + // `pop()` and `remove(0)`. + vec: PhantomData<&'a mut Vec> + start: *const T, + end: *const T, +} + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None +``` + +-- wait, this is seeming familiar. Let's do some more compression. Both +IntoIter and Drain have the exact same structure, let's just factor it out. + +```rust +struct RawValIter { + start: *const T, + end: *const T, +} + +impl RawValIter { + // unsafe to construct because it has no associated lifetimes. + // This is necessary to store a RawValIter in the same struct as + // its actual allocation. OK since it's a private implementation + // detail. + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if slice.len() == 0 { + // if `len = 0`, then this is not actually allocated memory. + // Need to avoid offsetting because that will give wrong + // information to LLVM via GEP. + slice.as_ptr() + } else { + slice.as_ptr().offset(slice.len() as isize) + } + } + } +} + +// Iterator and DoubleEndedIterator impls identical to IntoIter. +``` + +And IntoIter becomes the following: + +```rust,ignore +pub struct IntoIter { + _buf: RawVec, // we don't actually care about this. Just need it to live. + iter: RawValIter, +} + +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in &mut self.iter {} + } +} + +impl Vec { + pub fn into_iter(self) -> IntoIter { + unsafe { + let iter = RawValIter::new(&self); + + let buf = ptr::read(&self.buf); + mem::forget(self); + + IntoIter { + iter: iter, + _buf: buf, + } + } + } +} +``` + +Note that I've left a few quirks in this design to make upgrading Drain to work +with arbitrary subranges a bit easier. In particular we *could* have RawValIter +drain itself on drop, but that won't work right for a more complex Drain. +We also take a slice to simplify Drain initialization. + +Alright, now Drain is really easy: + +```rust,ignore +use std::marker::PhantomData; + +pub struct Drain<'a, T: 'a> { + vec: PhantomData<&'a mut Vec>, + iter: RawValIter, +} + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = T; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl<'a, T> DoubleEndedIterator for Drain<'a, T> { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +impl<'a, T> Drop for Drain<'a, T> { + fn drop(&mut self) { + for _ in &mut self.iter {} + } +} + +impl Vec { + pub fn drain(&mut self) -> Drain { + // this is a mem::forget safety thing. If Drain is forgotten, we just + // leak the whole Vec's contents. Also we need to do this eventually + // anyway, so why not do it now? + self.len = 0; + + unsafe { + Drain { + iter: RawValIter::new(&self), + vec: PhantomData, + } + } + } +} +``` + +For more details on the `mem::forget` problem, see the +[section on leaks][leaks]. + +[leaks]: leaking.html diff --git a/src/doc/nomicon/vec-final.md b/src/doc/nomicon/vec-final.md new file mode 100644 index 0000000000..847957e2ea --- /dev/null +++ b/src/doc/nomicon/vec-final.md @@ -0,0 +1,311 @@ +% The Final Code + +```rust +#![feature(unique)] +#![feature(heap_api)] + +use std::ptr::{Unique, self}; +use std::rt::heap; +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::marker::PhantomData; + + + + + +struct RawVec { + ptr: Unique, + cap: usize, +} + +impl RawVec { + fn new() -> Self { + unsafe { + // !0 is usize::MAX. This branch should be stripped at compile time. + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + + // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" + RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } + } + } + + fn grow(&mut self) { + unsafe { + let elem_size = mem::size_of::(); + + // since we set the capacity to usize::MAX when elem_size is + // 0, getting to here necessarily means the Vec is overfull. + assert!(elem_size != 0, "capacity overflow"); + + let align = mem::align_of::(); + + let (new_cap, ptr) = if self.cap == 0 { + let ptr = heap::allocate(elem_size, align); + (1, ptr) + } else { + let new_cap = 2 * self.cap; + let ptr = heap::reallocate(*self.ptr as *mut _, + self.cap * elem_size, + new_cap * elem_size, + align); + (new_cap, ptr) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } +} + +impl Drop for RawVec { + fn drop(&mut self) { + let elem_size = mem::size_of::(); + if self.cap != 0 && elem_size != 0 { + let align = mem::align_of::(); + + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.ptr as *mut _, num_bytes, align); + } + } + } +} + + + + + +pub struct Vec { + buf: RawVec, + len: usize, +} + +impl Vec { + fn ptr(&self) -> *mut T { *self.buf.ptr } + + fn cap(&self) -> usize { self.buf.cap } + + pub fn new() -> Self { + Vec { buf: RawVec::new(), len: 0 } + } + pub fn push(&mut self, elem: T) { + if self.len == self.cap() { self.buf.grow(); } + + unsafe { + ptr::write(self.ptr().offset(self.len as isize), elem); + } + + // Can't fail, we'll OOM first. + self.len += 1; + } + + pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + self.len -= 1; + unsafe { + Some(ptr::read(self.ptr().offset(self.len as isize))) + } + } + } + + pub fn insert(&mut self, index: usize, elem: T) { + assert!(index <= self.len, "index out of bounds"); + if self.cap() == self.len { self.buf.grow(); } + + unsafe { + if index < self.len { + ptr::copy(self.ptr().offset(index as isize), + self.ptr().offset(index as isize + 1), + self.len - index); + } + ptr::write(self.ptr().offset(index as isize), elem); + self.len += 1; + } + } + + pub fn remove(&mut self, index: usize) -> T { + assert!(index < self.len, "index out of bounds"); + unsafe { + self.len -= 1; + let result = ptr::read(self.ptr().offset(index as isize)); + ptr::copy(self.ptr().offset(index as isize + 1), + self.ptr().offset(index as isize), + self.len - index); + result + } + } + + pub fn into_iter(self) -> IntoIter { + unsafe { + let iter = RawValIter::new(&self); + let buf = ptr::read(&self.buf); + mem::forget(self); + + IntoIter { + iter: iter, + _buf: buf, + } + } + } + + pub fn drain(&mut self) -> Drain { + // this is a mem::forget safety thing. If this is forgotten, we just + // leak the whole Vec's contents. Also we need to do this *eventually* + // anyway, so why not do it now? + self.len = 0; + unsafe { + Drain { + iter: RawValIter::new(&self), + vec: PhantomData, + } + } + } +} + +impl Drop for Vec { + fn drop(&mut self) { + while let Some(_) = self.pop() {} + // allocation is handled by RawVec + } +} + +impl Deref for Vec { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { + ::std::slice::from_raw_parts(self.ptr(), self.len) + } + } +} + +impl DerefMut for Vec { + fn deref_mut(&mut self) -> &mut [T] { + unsafe { + ::std::slice::from_raw_parts_mut(self.ptr(), self.len) + } + } +} + + + + + +struct RawValIter { + start: *const T, + end: *const T, +} + +impl RawValIter { + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if mem::size_of::() == 0 { + ((slice.as_ptr() as usize) + slice.len()) as *const _ + } else if slice.len() == 0 { + slice.as_ptr() + } else { + slice.as_ptr().offset(slice.len() as isize) + } + } + } +} + +impl Iterator for RawValIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + let result = ptr::read(self.start); + self.start = self.start.offset(1); + Some(result) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let elem_size = mem::size_of::(); + let len = (self.end as usize - self.start as usize) + / if elem_size == 0 { 1 } else { elem_size }; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for RawValIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + self.end = self.end.offset(-1); + Some(ptr::read(self.end)) + } + } + } +} + + + + +pub struct IntoIter { + _buf: RawVec, // we don't actually care about this. Just need it to live. + iter: RawValIter, +} + +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in &mut *self {} + } +} + + + + +pub struct Drain<'a, T: 'a> { + vec: PhantomData<&'a mut Vec>, + iter: RawValIter, +} + +impl<'a, T> Iterator for Drain<'a, T> { + type Item = T; + fn next(&mut self) -> Option { self.iter.next_back() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +impl<'a, T> DoubleEndedIterator for Drain<'a, T> { + fn next_back(&mut self) -> Option { self.iter.next_back() } +} + +impl<'a, T> Drop for Drain<'a, T> { + fn drop(&mut self) { + // pre-drain the iter + for _ in &mut self.iter {} + } +} + +/// Abort the process, we're out of memory! +/// +/// In practice this is probably dead code on most OSes +fn oom() { + ::std::process::exit(-9999); +} + +# fn main() {} +``` diff --git a/src/doc/nomicon/vec-insert-remove.md b/src/doc/nomicon/vec-insert-remove.md new file mode 100644 index 0000000000..0a37170c52 --- /dev/null +++ b/src/doc/nomicon/vec-insert-remove.md @@ -0,0 +1,51 @@ +% Insert and Remove + +Something *not* provided by slice is `insert` and `remove`, so let's do those +next. + +Insert needs to shift all the elements at the target index to the right by one. +To do this we need to use `ptr::copy`, which is our version of C's `memmove`. +This copies some chunk of memory from one location to another, correctly +handling the case where the source and destination overlap (which will +definitely happen here). + +If we insert at index `i`, we want to shift the `[i .. len]` to `[i+1 .. len+1]` +using the old len. + +```rust,ignore +pub fn insert(&mut self, index: usize, elem: T) { + // Note: `<=` because it's valid to insert after everything + // which would be equivalent to push. + assert!(index <= self.len, "index out of bounds"); + if self.cap == self.len { self.grow(); } + + unsafe { + if index < self.len { + // ptr::copy(src, dest, len): "copy from source to dest len elems" + ptr::copy(self.ptr.offset(index as isize), + self.ptr.offset(index as isize + 1), + len - index); + } + ptr::write(self.ptr.offset(index as isize), elem); + self.len += 1; + } +} +``` + +Remove behaves in the opposite manner. We need to shift all the elements from +`[i+1 .. len + 1]` to `[i .. len]` using the *new* len. + +```rust,ignore +pub fn remove(&mut self, index: usize) -> T { + // Note: `<` because it's *not* valid to remove after everything + assert!(index < self.len, "index out of bounds"); + unsafe { + self.len -= 1; + let result = ptr::read(self.ptr.offset(index as isize)); + ptr::copy(self.ptr.offset(index as isize + 1), + self.ptr.offset(index as isize), + len - index); + result + } +} +``` diff --git a/src/doc/nomicon/vec-into-iter.md b/src/doc/nomicon/vec-into-iter.md new file mode 100644 index 0000000000..ebb0a79bb6 --- /dev/null +++ b/src/doc/nomicon/vec-into-iter.md @@ -0,0 +1,147 @@ +% IntoIter + +Let's move on to writing iterators. `iter` and `iter_mut` have already been +written for us thanks to The Magic of Deref. However there's two interesting +iterators that Vec provides that slices can't: `into_iter` and `drain`. + +IntoIter consumes the Vec by-value, and can consequently yield its elements +by-value. In order to enable this, IntoIter needs to take control of Vec's +allocation. + +IntoIter needs to be DoubleEnded as well, to enable reading from both ends. +Reading from the back could just be implemented as calling `pop`, but reading +from the front is harder. We could call `remove(0)` but that would be insanely +expensive. Instead we're going to just use ptr::read to copy values out of +either end of the Vec without mutating the buffer at all. + +To do this we're going to use a very common C idiom for array iteration. We'll +make two pointers; one that points to the start of the array, and one that +points to one-element past the end. When we want an element from one end, we'll +read out the value pointed to at that end and move the pointer over by one. When +the two pointers are equal, we know we're done. + +Note that the order of read and offset are reversed for `next` and `next_back` +For `next_back` the pointer is always after the element it wants to read next, +while for `next` the pointer is always at the element it wants to read next. +To see why this is, consider the case where every element but one has been +yielded. + +The array looks like this: + +```text + S E +[X, X, X, O, X, X, X] +``` + +If E pointed directly at the element it wanted to yield next, it would be +indistinguishable from the case where there are no more elements to yield. + +Although we don't actually care about it during iteration, we also need to hold +onto the Vec's allocation information in order to free it once IntoIter is +dropped. + +So we're going to use the following struct: + +```rust,ignore +struct IntoIter { + buf: Unique, + cap: usize, + start: *const T, + end: *const T, +} +``` + +And this is what we end up with for initialization: + +```rust,ignore +impl Vec { + fn into_iter(self) -> IntoIter { + // Can't destructure Vec since it's Drop + let ptr = self.ptr; + let cap = self.cap; + let len = self.len; + + // Make sure not to drop Vec since that will free the buffer + mem::forget(self); + + unsafe { + IntoIter { + buf: ptr, + cap: cap, + start: *ptr, + end: if cap == 0 { + // can't offset off this pointer, it's not allocated! + *ptr + } else { + ptr.offset(len as isize) + } + } + } + } +} +``` + +Here's iterating forward: + +```rust,ignore +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + let result = ptr::read(self.start); + self.start = self.start.offset(1); + Some(result) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = (self.end as usize - self.start as usize) + / mem::size_of::(); + (len, Some(len)) + } +} +``` + +And here's iterating backwards. + +```rust,ignore +impl DoubleEndedIterator for IntoIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + self.end = self.end.offset(-1); + Some(ptr::read(self.end)) + } + } + } +} +``` + +Because IntoIter takes ownership of its allocation, it needs to implement Drop +to free it. However it also wants to implement Drop to drop any elements it +contains that weren't yielded. + + +```rust,ignore +impl Drop for IntoIter { + fn drop(&mut self) { + if self.cap != 0 { + // drop any remaining elements + for _ in &mut *self {} + + let align = mem::align_of::(); + let elem_size = mem::size_of::(); + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.buf as *mut _, num_bytes, align); + } + } + } +} +``` diff --git a/src/doc/nomicon/vec-layout.md b/src/doc/nomicon/vec-layout.md new file mode 100644 index 0000000000..3df63d5249 --- /dev/null +++ b/src/doc/nomicon/vec-layout.md @@ -0,0 +1,100 @@ +% Layout + +First off, we need to come up with the struct layout. A Vec has three parts: +a pointer to the allocation, the size of the allocation, and the number of +elements that have been initialized. + +Naively, this means we just want this design: + +```rust +pub struct Vec { + ptr: *mut T, + cap: usize, + len: usize, +} +# fn main() {} +``` + +And indeed this would compile. Unfortunately, it would be incorrect. First, the +compiler will give us too strict variance. So a `&Vec<&'static str>` +couldn't be used where an `&Vec<&'a str>` was expected. More importantly, it +will give incorrect ownership information to the drop checker, as it will +conservatively assume we don't own any values of type `T`. See [the chapter +on ownership and lifetimes][ownership] for all the details on variance and +drop check. + +As we saw in the ownership chapter, we should use `Unique` in place of +`*mut T` when we have a raw pointer to an allocation we own. Unique is unstable, +so we'd like to not use it if possible, though. + +As a recap, Unique is a wrapper around a raw pointer that declares that: + +* We are variant over `T` +* We may own a value of type `T` (for drop check) +* We are Send/Sync if `T` is Send/Sync +* We deref to `*mut T` (so it largely acts like a `*mut` in our code) +* Our pointer is never null (so `Option>` is null-pointer-optimized) + +We can implement all of the above requirements except for the last +one in stable Rust: + +```rust +use std::marker::PhantomData; +use std::ops::Deref; +use std::mem; + +struct Unique { + ptr: *const T, // *const for variance + _marker: PhantomData, // For the drop checker +} + +// Deriving Send and Sync is safe because we are the Unique owners +// of this data. It's like Unique is "just" T. +unsafe impl Send for Unique {} +unsafe impl Sync for Unique {} + +impl Unique { + pub fn new(ptr: *mut T) -> Self { + Unique { ptr: ptr, _marker: PhantomData } + } +} + +impl Deref for Unique { + type Target = *mut T; + fn deref(&self) -> &*mut T { + // There's no way to cast the *const to a *mut + // while also taking a reference. So we just + // transmute it since it's all "just pointers". + unsafe { mem::transmute(&self.ptr) } + } +} +# fn main() {} +``` + +Unfortunately the mechanism for stating that your value is non-zero is +unstable and unlikely to be stabilized soon. As such we're just going to +take the hit and use std's Unique: + + +```rust +#![feature(unique)] + +use std::ptr::{Unique, self}; + +pub struct Vec { + ptr: Unique, + cap: usize, + len: usize, +} + +# fn main() {} +``` + +If you don't care about the null-pointer optimization, then you can use the +stable code. However we will be designing the rest of the code around enabling +the optimization. In particular, `Unique::new` is unsafe to call, because +putting `null` inside of it is Undefined Behaviour. Our stable Unique doesn't +need `new` to be unsafe because it doesn't make any interesting guarantees about +its contents. + +[ownership]: ownership.html diff --git a/src/doc/nomicon/vec-push-pop.md b/src/doc/nomicon/vec-push-pop.md new file mode 100644 index 0000000000..b518e8aa48 --- /dev/null +++ b/src/doc/nomicon/vec-push-pop.md @@ -0,0 +1,55 @@ +% Push and Pop + +Alright. We can initialize. We can allocate. Let's actually implement some +functionality! Let's start with `push`. All it needs to do is check if we're +full to grow, unconditionally write to the next index, and then increment our +length. + +To do the write we have to be careful not to evaluate the memory we want to write +to. At worst, it's truly uninitialized memory from the allocator. At best it's the +bits of some old value we popped off. Either way, we can't just index to the memory +and dereference it, because that will evaluate the memory as a valid instance of +T. Worse, `foo[idx] = x` will try to call `drop` on the old value of `foo[idx]`! + +The correct way to do this is with `ptr::write`, which just blindly overwrites the +target address with the bits of the value we provide. No evaluation involved. + +For `push`, if the old len (before push was called) is 0, then we want to write +to the 0th index. So we should offset by the old len. + +```rust,ignore +pub fn push(&mut self, elem: T) { + if self.len == self.cap { self.grow(); } + + unsafe { + ptr::write(self.ptr.offset(self.len as isize), elem); + } + + // Can't fail, we'll OOM first. + self.len += 1; +} +``` + +Easy! How about `pop`? Although this time the index we want to access is +initialized, Rust won't just let us dereference the location of memory to move +the value out, because that would leave the memory uninitialized! For this we +need `ptr::read`, which just copies out the bits from the target address and +intrprets it as a value of type T. This will leave the memory at this address +logically uninitialized, even though there is in fact a perfectly good instance +of T there. + +For `pop`, if the old len is 1, we want to read out of the 0th index. So we +should offset by the new len. + +```rust,ignore +pub fn pop(&mut self) -> Option { + if self.len == 0 { + None + } else { + self.len -= 1; + unsafe { + Some(ptr::read(self.ptr.offset(self.len as isize))) + } + } +} +``` diff --git a/src/doc/nomicon/vec-raw.md b/src/doc/nomicon/vec-raw.md new file mode 100644 index 0000000000..8f78462cf4 --- /dev/null +++ b/src/doc/nomicon/vec-raw.md @@ -0,0 +1,136 @@ +% RawVec + +We've actually reached an interesting situation here: we've duplicated the logic +for specifying a buffer and freeing its memory in Vec and IntoIter. Now that +we've implemented it and identified *actual* logic duplication, this is a good +time to perform some logic compression. + +We're going to abstract out the `(ptr, cap)` pair and give them the logic for +allocating, growing, and freeing: + +```rust,ignore +struct RawVec { + ptr: Unique, + cap: usize, +} + +impl RawVec { + fn new() -> Self { + assert!(mem::size_of::() != 0, "TODO: implement ZST support"); + unsafe { + RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: 0 } + } + } + + // unchanged from Vec + fn grow(&mut self) { + unsafe { + let align = mem::align_of::(); + let elem_size = mem::size_of::(); + + let (new_cap, ptr) = if self.cap == 0 { + let ptr = heap::allocate(elem_size, align); + (1, ptr) + } else { + let new_cap = 2 * self.cap; + let ptr = heap::reallocate(*self.ptr as *mut _, + self.cap * elem_size, + new_cap * elem_size, + align); + (new_cap, ptr) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } +} + + +impl Drop for RawVec { + fn drop(&mut self) { + if self.cap != 0 { + let align = mem::align_of::(); + let elem_size = mem::size_of::(); + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.ptr as *mut _, num_bytes, align); + } + } + } +} +``` + +And change Vec as follows: + +```rust,ignore +pub struct Vec { + buf: RawVec, + len: usize, +} + +impl Vec { + fn ptr(&self) -> *mut T { *self.buf.ptr } + + fn cap(&self) -> usize { self.buf.cap } + + pub fn new() -> Self { + Vec { buf: RawVec::new(), len: 0 } + } + + // push/pop/insert/remove largely unchanged: + // * `self.ptr -> self.ptr()` + // * `self.cap -> self.cap()` + // * `self.grow -> self.buf.grow()` +} + +impl Drop for Vec { + fn drop(&mut self) { + while let Some(_) = self.pop() {} + // deallocation is handled by RawVec + } +} +``` + +And finally we can really simplify IntoIter: + +```rust,ignore +struct IntoIter { + _buf: RawVec, // we don't actually care about this. Just need it to live. + start: *const T, + end: *const T, +} + +// next and next_back literally unchanged since they never referred to the buf + +impl Drop for IntoIter { + fn drop(&mut self) { + // only need to ensure all our elements are read; + // buffer will clean itself up afterwards. + for _ in &mut *self {} + } +} + +impl Vec { + pub fn into_iter(self) -> IntoIter { + unsafe { + // need to use ptr::read to unsafely move the buf out since it's + // not Copy, and Vec implements Drop (so we can't destructure it). + let buf = ptr::read(&self.buf); + let len = self.len; + mem::forget(self); + + IntoIter { + start: *buf.ptr, + end: buf.ptr.offset(len as isize), + _buf: buf, + } + } + } +} +``` + +Much better. diff --git a/src/doc/nomicon/vec-zsts.md b/src/doc/nomicon/vec-zsts.md new file mode 100644 index 0000000000..72e8a34488 --- /dev/null +++ b/src/doc/nomicon/vec-zsts.md @@ -0,0 +1,176 @@ +% Handling Zero-Sized Types + +It's time. We're going to fight the spectre that is zero-sized types. Safe Rust +*never* needs to care about this, but Vec is very intensive on raw pointers and +raw allocations, which are exactly the two things that care about +zero-sized types. We need to be careful of two things: + +* The raw allocator API has undefined behaviour if you pass in 0 for an + allocation size. +* raw pointer offsets are no-ops for zero-sized types, which will break our + C-style pointer iterator. + +Thankfully we abstracted out pointer-iterators and allocating handling into +RawValIter and RawVec respectively. How mysteriously convenient. + + + + +## Allocating Zero-Sized Types + +So if the allocator API doesn't support zero-sized allocations, what on earth +do we store as our allocation? Why, `heap::EMPTY` of course! Almost every operation +with a ZST is a no-op since ZSTs have exactly one value, and therefore no state needs +to be considered to store or load them. This actually extends to `ptr::read` and +`ptr::write`: they won't actually look at the pointer at all. As such we never need +to change the pointer. + +Note however that our previous reliance on running out of memory before overflow is +no longer valid with zero-sized types. We must explicitly guard against capacity +overflow for zero-sized types. + +Due to our current architecture, all this means is writing 3 guards, one in each +method of RawVec. + +```rust,ignore +impl RawVec { + fn new() -> Self { + unsafe { + // !0 is usize::MAX. This branch should be stripped at compile time. + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + + // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" + RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } + } + } + + fn grow(&mut self) { + unsafe { + let elem_size = mem::size_of::(); + + // since we set the capacity to usize::MAX when elem_size is + // 0, getting to here necessarily means the Vec is overfull. + assert!(elem_size != 0, "capacity overflow"); + + let align = mem::align_of::(); + + let (new_cap, ptr) = if self.cap == 0 { + let ptr = heap::allocate(elem_size, align); + (1, ptr) + } else { + let new_cap = 2 * self.cap; + let ptr = heap::reallocate(*self.ptr as *mut _, + self.cap * elem_size, + new_cap * elem_size, + align); + (new_cap, ptr) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } +} + +impl Drop for RawVec { + fn drop(&mut self) { + let elem_size = mem::size_of::(); + + // don't free zero-sized allocations, as they were never allocated. + if self.cap != 0 && elem_size != 0 { + let align = mem::align_of::(); + + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.ptr as *mut _, num_bytes, align); + } + } + } +} +``` + +That's it. We support pushing and popping zero-sized types now. Our iterators +(that aren't provided by slice Deref) are still busted, though. + + + + +## Iterating Zero-Sized Types + +Zero-sized offsets are no-ops. This means that our current design will always +initialize `start` and `end` as the same value, and our iterators will yield +nothing. The current solution to this is to cast the pointers to integers, +increment, and then cast them back: + +```rust,ignore +impl RawValIter { + unsafe fn new(slice: &[T]) -> Self { + RawValIter { + start: slice.as_ptr(), + end: if mem::size_of::() == 0 { + ((slice.as_ptr() as usize) + slice.len()) as *const _ + } else if slice.len() == 0 { + slice.as_ptr() + } else { + slice.as_ptr().offset(slice.len() as isize) + } + } + } +} +``` + +Now we have a different bug. Instead of our iterators not running at all, our +iterators now run *forever*. We need to do the same trick in our iterator impls. +Also, our size_hint computation code will divide by 0 for ZSTs. Since we'll +basically be treating the two pointers as if they point to bytes, we'll just +map size 0 to divide by 1. + +```rust,ignore +impl Iterator for RawValIter { + type Item = T; + fn next(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + let result = ptr::read(self.start); + self.start = if mem::size_of::() == 0 { + (self.start as usize + 1) as *const _ + } else { + self.start.offset(1); + } + Some(result) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let elem_size = mem::size_of::(); + let len = (self.end as usize - self.start as usize) + / if elem_size == 0 { 1 } else { elem_size }; + (len, Some(len)) + } +} + +impl DoubleEndedIterator for RawValIter { + fn next_back(&mut self) -> Option { + if self.start == self.end { + None + } else { + unsafe { + self.end = if mem::size_of::() == 0 { + (self.end as usize - 1) as *const _ + } else { + self.end.offset(-1); + } + Some(ptr::read(self.end)) + } + } + } +} +``` + +And that's it. Iteration works! diff --git a/src/doc/nomicon/vec.md b/src/doc/nomicon/vec.md new file mode 100644 index 0000000000..63f83788c4 --- /dev/null +++ b/src/doc/nomicon/vec.md @@ -0,0 +1,20 @@ +% Example: Implementing Vec + +To bring everything together, we're going to write `std::Vec` from scratch. +Because all the best tools for writing unsafe code are unstable, this +project will only work on nightly (as of Rust 1.2.0). With the exception of the +allocator API, much of the unstable code we'll use is expected to be stabilized +in a similar form as it is today. + +However we will generally try to avoid unstable code where possible. In +particular we won't use any intrinsics that could make a code a little +bit nicer or efficient because intrinsics are permanently unstable. Although +many intrinsics *do* become stabilized elsewhere (`std::ptr` and `str::mem` +consist of many intrinsics). + +Ultimately this means our implementation may not take advantage of all +possible optimizations, though it will be by no means *naive*. We will +definitely get into the weeds over nitty-gritty details, even +when the problem doesn't *really* merit it. + +You wanted advanced. We're gonna go advanced. diff --git a/src/doc/nomicon/working-with-unsafe.md b/src/doc/nomicon/working-with-unsafe.md new file mode 100644 index 0000000000..b20dff72e1 --- /dev/null +++ b/src/doc/nomicon/working-with-unsafe.md @@ -0,0 +1,119 @@ +% Working with Unsafe + +Rust generally only gives us the tools to talk about Unsafe Rust in a scoped and +binary manner. Unfortunately, reality is significantly more complicated than +that. For instance, consider the following toy function: + +```rust +fn index(idx: usize, arr: &[u8]) -> Option { + if idx < arr.len() { + unsafe { + Some(*arr.get_unchecked(idx)) + } + } else { + None + } +} +``` + +Clearly, this function is safe. We check that the index is in bounds, and if it +is, index into the array in an unchecked manner. But even in such a trivial +function, the scope of the unsafe block is questionable. Consider changing the +`<` to a `<=`: + +```rust +fn index(idx: usize, arr: &[u8]) -> Option { + if idx <= arr.len() { + unsafe { + Some(*arr.get_unchecked(idx)) + } + } else { + None + } +} +``` + +This program is now unsound, and yet *we only modified safe code*. This is the +fundamental problem of safety: it's non-local. The soundness of our unsafe +operations necessarily depends on the state established by otherwise +"safe" operations. + +Safety is modular in the sense that opting into unsafety doesn't require you +to consider arbitrary other kinds of badness. For instance, doing an unchecked +index into a slice doesn't mean you suddenly need to worry about the slice being +null or containing uninitialized memory. Nothing fundamentally changes. However +safety *isn't* modular in the sense that programs are inherently stateful and +your unsafe operations may depend on arbitrary other state. + +Trickier than that is when we get into actual statefulness. Consider a simple +implementation of `Vec`: + +```rust +use std::ptr; + +// Note this definition is insufficient. See the section on implementing Vec. +pub struct Vec { + ptr: *mut T, + len: usize, + cap: usize, +} + +// Note this implementation does not correctly handle zero-sized types. +// We currently live in a nice imaginary world of only positive fixed-size +// types. +impl Vec { + pub fn push(&mut self, elem: T) { + if self.len == self.cap { + // not important for this example + self.reallocate(); + } + unsafe { + ptr::write(self.ptr.offset(self.len as isize), elem); + self.len += 1; + } + } + + # fn reallocate(&mut self) { } +} + +# fn main() {} +``` + +This code is simple enough to reasonably audit and verify. Now consider +adding the following method: + +```rust,ignore +fn make_room(&mut self) { + // grow the capacity + self.cap += 1; +} +``` + +This code is 100% Safe Rust but it is also completely unsound. Changing the +capacity violates the invariants of Vec (that `cap` reflects the allocated space +in the Vec). This is not something the rest of Vec can guard against. It *has* +to trust the capacity field because there's no way to verify it. + +`unsafe` does more than pollute a whole function: it pollutes a whole *module*. +Generally, the only bullet-proof way to limit the scope of unsafe code is at the +module boundary with privacy. + +However this works *perfectly*. The existence of `make_room` is *not* a +problem for the soundness of Vec because we didn't mark it as public. Only the +module that defines this function can call it. Also, `make_room` directly +accesses the private fields of Vec, so it can only be written in the same module +as Vec. + +It is therefore possible for us to write a completely safe abstraction that +relies on complex invariants. This is *critical* to the relationship between +Safe Rust and Unsafe Rust. We have already seen that Unsafe code must trust +*some* Safe code, but can't trust *generic* Safe code. It can't trust an +arbitrary implementor of a trait or any function that was passed to it to be +well-behaved in a way that safe code doesn't care about. + +However if unsafe code couldn't prevent client safe code from messing with its +state in arbitrary ways, safety would be a lost cause. Thankfully, it *can* +prevent arbitrary code from messing with critical state due to privacy. + +Safety lives! + diff --git a/src/doc/reference.md b/src/doc/reference.md index a3e13accca..5988d62bd7 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -338,12 +338,16 @@ type of the literal. The integer suffix must be the name of one of the integral types: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `isize`, or `usize`. -The type of an _unsuffixed_ integer literal is determined by type inference. -If an integer type can be _uniquely_ determined from the surrounding program -context, the unsuffixed integer literal has that type. If the program context -underconstrains the type, it defaults to the signed 32-bit integer `i32`; if -the program context overconstrains the type, it is considered a static type -error. +The type of an _unsuffixed_ integer literal is determined by type inference: + +* If an integer type can be _uniquely_ determined from the surrounding + program context, the unsuffixed integer literal has that type. + +* If the program context under-constrains the type, it defaults to the + signed 32-bit integer `i32`. + +* If the program context over-constrains the type, it is considered a + static type error. Examples of integer literals of various forms: @@ -371,12 +375,17 @@ The suffix forcibly sets the type of the literal. There are two valid _floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point types), which explicitly determine the type of the literal. -The type of an _unsuffixed_ floating-point literal is determined by type -inference. If a floating-point type can be _uniquely_ determined from the -surrounding program context, the unsuffixed floating-point literal has that type. -If the program context underconstrains the type, it defaults to double-precision `f64`; -if the program context overconstrains the type, it is considered a static type -error. +The type of an _unsuffixed_ floating-point literal is determined by +type inference: + +* If a floating-point type can be _uniquely_ determined from the + surrounding program context, the unsuffixed floating-point literal + has that type. + +* If the program context under-constrains the type, it defaults to `f64`. + +* If the program context over-constrains the type, it is considered a + static type error. Examples of floating-point literals of various forms: @@ -582,8 +591,9 @@ always been designed to be compiled. For these reasons, this section assumes a compiler. Rust's semantics obey a *phase distinction* between compile-time and -run-time.[^phase-distinction] Those semantic rules that have a *static -interpretation* govern the success or failure of compilation. Those semantics +run-time.[^phase-distinction] Semantic rules that have a *static +interpretation* govern the success or failure of compilation, while +semantic rules that have a *dynamic interpretation* govern the behavior of the program at run-time. @@ -1047,11 +1057,8 @@ This is a list of behavior not considered *unsafe* in Rust terms, but that may be undesired. * Deadlocks -* Reading data from private fields (`std::repr`) * Leaks of memory and other resources * Exiting without calling destructors -* Sending signals -* Accessing/modifying the file system * Integer overflow - Overflow is considered "unexpected" behavior and is always user-error, unless the `wrapping` primitives are used. In non-optimized builds, the compiler @@ -1192,8 +1199,8 @@ An example of an `enum` item and its use: ``` enum Animal { - Dog, - Cat + Dog, + Cat, } let mut a: Animal = Animal::Dog; @@ -1286,7 +1293,7 @@ All access to a static is safe, but there are a number of restrictions on statics: * Statics may not contain any destructors. -* The types of static values must ascribe to `Sync` to allow threadsafe access. +* The types of static values must ascribe to `Sync` to allow thread-safe access. * Statics may not refer to other statics by value, only by reference. * Constants cannot refer to statics. @@ -1630,6 +1637,10 @@ The type of a function declared in an extern block is `extern "abi" fn(A1, ..., An) -> R`, where `A1...An` are the declared types of its arguments and `R` is the declared return type. +It is valid to add the `link` attribute on an empty extern block. You can use +this to satisfy the linking requirements of extern blocks elsewhere in your code +(including upstream crates) instead of adding the attribute to each extern block. + ## Visibility and Privacy These two terms are often used interchangeably, and what they are attempting to @@ -1688,7 +1699,7 @@ explain, here's a few use cases and what they would entail: * A crate needs a global available "helper module" to itself, but it doesn't want to expose the helper module as a public API. To accomplish this, the root of the crate's hierarchy would have a private module which then - internally has a "public api". Because the entire crate is a descendant of + internally has a "public API". Because the entire crate is a descendant of the root, then the entire local crate can access this private module through the second case. @@ -1951,8 +1962,6 @@ macro scope. object file that this item's contents will be placed into. - `no_mangle` - on any item, do not apply the standard name mangling. Set the symbol for this item to its identifier. -- `packed` - on structs or enums, eliminate any padding that would be used to - align fields. - `simd` - on certain tuple structs, derive the arithmetic operators, which lower to the target's SIMD instructions, if any; the `simd` feature gate is necessary to use this attribute. @@ -2026,7 +2035,7 @@ The following configurations must be defined by the implementation: as a configuration itself, like `unix` or `windows`. * `target_os = "..."`. Operating system of the target, examples include `"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`, - `"bitrig"` or `"openbsd"`. + `"bitrig"` , `"openbsd"` or `"netbsd"`. * `target_pointer_width = "..."`. Target pointer width in bits. This is set to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for 64-bit pointers. @@ -2360,6 +2369,8 @@ The currently implemented features of the reference compiler are: internally without imposing on callers (i.e. making them behave like function calls in terms of encapsulation). +* - `default_type_parameter_fallback` - Allows type parameter defaults to + influence type inference. If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled @@ -2509,9 +2520,8 @@ Here are some examples: #### Moved and copied types When a [local variable](#variables) is used as an -[rvalue](#lvalues,-rvalues-and-temporaries) the variable will either be moved -or copied, depending on its type. All values whose type implements `Copy` are -copied, all others are moved. +[rvalue](#lvalues,-rvalues-and-temporaries), the variable will be copied +if its type implements `Copy`. All others are moved. ### Literal expressions @@ -2876,7 +2886,6 @@ operand. ``` # let mut x = 0; # let y = 0; - x = y; ``` @@ -2966,14 +2975,12 @@ move values (depending on their type) from the environment into the lambda expression's captured environment. In this example, we define a function `ten_times` that takes a higher-order -function argument, and call it with a lambda expression as an argument: +function argument, and we then call it with a lambda expression as an argument: ``` fn ten_times(f: F) where F: Fn(i32) { - let mut i = 0i32; - while i < 10 { - f(i); - i += 1; + for index in 0..10 { + f(index); } } @@ -3322,10 +3329,13 @@ An example of a tuple type and its use: ``` type Pair<'a> = (i32, &'a str); -let p: Pair<'static> = (10, "hello"); +let p: Pair<'static> = (10, "ten"); let (a, b) = p; -assert!(b != "world"); -assert!(p.0 == 10); + +assert_eq!(a, 10); +assert_eq!(b, "ten"); +assert_eq!(p.0, 10); +assert_eq!(p.1, "ten"); ``` For historical reasons and convenience, the tuple type with no elements (`()`) @@ -3335,8 +3345,8 @@ is often called ‘unit’ or ‘the unit type’. Rust has two different types for a list of items: -* `[T; N]`, an 'array'. -* `&[T]`, a 'slice'. +* `[T; N]`, an 'array' +* `&[T]`, a 'slice' An array has a fixed size, and can be allocated on either the stack or the heap. @@ -3344,18 +3354,23 @@ heap. A slice is a 'view' into an array. It doesn't own the data it points to, it borrows it. -An example of each kind: +Examples: ```{rust} -let vec: Vec = vec![1, 2, 3]; -let arr: [i32; 3] = [1, 2, 3]; -let s: &[i32] = &vec[..]; +// A stack-allocated array +let array: [i32; 3] = [1, 2, 3]; + +// A heap-allocated array +let vector: Vec = vec![1, 2, 3]; + +// A slice into an array +let slice: &[i32] = &vector[..]; ``` As you can see, the `vec!` macro allows you to create a `Vec` easily. The `vec!` macro is also part of the standard library, rather than the language. -All in-bounds elements of arrays, and slices are always initialized, and access +All in-bounds elements of arrays and slices are always initialized, and access to an array or slice is always bounds-checked. ### Structure types @@ -3489,7 +3504,7 @@ x = bo(5,7); #### Function types for specific items -Internally to the compiler, there are also function types that are specific to a particular +Internal to the compiler, there are also function types that are specific to a particular function item. In the following snippet, for example, the internal types of the functions `foo` and `bar` are different, despite the fact that they have the same signature: @@ -3517,13 +3532,14 @@ more of the closure traits: * `FnMut` : The closure can be called multiple times as mutable. A closure called as - `FnMut` can mutate values from its environment. `FnMut` implies - `FnOnce`. + `FnMut` can mutate values from its environment. `FnMut` inherits from + `FnOnce` (i.e. anything implementing `FnMut` also implements `FnOnce`). * `Fn` : The closure can be called multiple times through a shared reference. A closure called as `Fn` can neither move out from nor mutate values - from its environment. `Fn` implies `FnMut` and `FnOnce`. + from its environment. `Fn` inherits from `FnMut`, which itself + inherits from `FnOnce`. ### Trait objects @@ -3646,53 +3662,77 @@ Coercions are defined in [RFC401]. A coercion is implicit and has no syntax. ### Coercion sites A coercion can only occur at certain coercion sites in a program; these are -typically places where the desired type is explicit or can be dervied by +typically places where the desired type is explicit or can be derived by propagation from explicit types (without type inference). Possible coercion sites are: * `let` statements where an explicit type is given. - In `let _: U = e;`, `e` is coerced to have type `U`. + For example, `128` is coerced to have type `i8` in the following: + + ```rust + let _: i8 = 128; + ``` * `static` and `const` statements (similar to `let` statements). -* arguments for function calls. +* Arguments for function calls + + The value being coerced is the actual parameter, and it is coerced to + the type of the formal parameter. - The value being coerced is the - actual parameter and it is coerced to the type of the formal parameter. For - example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as - `foo(e);`. Then `e` is coerced to have type `U`; + For example, `128` is coerced to have type `i8` in the following: -* instantiations of struct or variant fields. + ```rust + fn bar(_: i8) { } - Assume we have a `struct - Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to - have type `U`. + fn main() { + bar(128); + } + ``` -* function results (either the final line of a block if it is not semicolon -terminated or any expression in a `return` statement). +* Instantiations of struct or variant fields - In `fn foo() -> U { e }`, `e` is coerced to to have type `U`. + For example, `128` is coerced to have type `i8` in the following: + + ```rust + struct Foo { x: i8 } + + fn main() { + Foo { x: 128 }; + } + ``` + +* Function results, either the final line of a block if it is not + semicolon-terminated or any expression in a `return` statement + + For example, `128` is coerced to have type `i8` in the following: + + ```rust + fn foo() -> i8 { + 128 + } + ``` If the expression in one of these coercion sites is a coercion-propagating expression, then the relevant sub-expressions in that expression are also coercion sites. Propagation recurses from these new coercion sites. Propagating expressions and their relevant sub-expressions are: -* array literals, where the array has type `[U; n]`. Each sub-expression in +* Array literals, where the array has type `[U; n]`. Each sub-expression in the array literal is a coercion site for coercion to type `U`. -* array literals with repeating syntax, where the array has type `[U; n]`. The +* Array literals with repeating syntax, where the array has type `[U; n]`. The repeated sub-expression is a coercion site for coercion to type `U`. -* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. +* Tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. Each sub-expression is a coercion site to the respective type, e.g. the zeroth sub-expression is a coercion site to type `U_0`. -* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then +* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then the sub-expression is a coercion site to `U`. -* blocks. If a block has type `U`, then the last expression in the block (if +* Blocks: if a block has type `U`, then the last expression in the block (if it is not semicolon-terminated) is a coercion site to `U`. This includes blocks which are part of control flow statements, such as `if`/`else`, if the block has a known type. @@ -3701,45 +3741,46 @@ the block has a known type. Coercion is allowed between the following types: -* `T` to `U` if `T` is a subtype of `U` (*reflexive case*). +* `T` to `U` if `T` is a subtype of `U` (*reflexive case*) * `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` -(*transitive case*). +(*transitive case*) Note that this is not fully supported yet -* `&mut T` to `&T`. +* `&mut T` to `&T` -* `*mut T` to `*const T`. +* `*mut T` to `*const T` -* `&T` to `*const T`. +* `&T` to `*const T` -* `&mut T` to `*mut T`. +* `&mut T` to `*mut T` * `&T` to `&U` if `T` implements `Deref`. For example: -```rust -use std::ops::Deref; + ```rust + use std::ops::Deref; -struct CharContainer { - value: char -} + struct CharContainer { + value: char + } -impl Deref for CharContainer { - type Target = char; + impl Deref for CharContainer { + type Target = char; - fn deref<'a>(&'a self) -> &'a char { - &self.value - } -} + fn deref<'a>(&'a self) -> &'a char { + &self.value + } + } -fn foo(arg: &char) {} + fn foo(arg: &char) {} + + fn main() { + let x = &mut CharContainer { value: 'y' }; + foo(x); //&mut CharContainer is coerced to &char. + } + ``` -fn main() { - let x = &mut CharContainer { value: 'y' }; - foo(x); //&mut CharContainer is coerced to &char. -} -``` * `&mut T` to `&mut U` if `T` implements `DerefMut`. * TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of @@ -3953,7 +3994,7 @@ In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for all compilation needs, and the other options are just available if more fine-grained control is desired over the output format of a Rust crate. -# Appendix: Rationales and design tradeoffs +# Appendix: Rationales and design trade-offs *TODO*. @@ -3963,7 +4004,7 @@ Rust is not a particularly original language, with design elements coming from a wide range of sources. Some of these are listed below (including elements that have since been removed): -* SML, OCaml: algebraic datatypes, pattern matching, type inference, +* SML, OCaml: algebraic data types, pattern matching, type inference, semicolon statement separation * C++: references, RAII, smart pointers, move semantics, monomorphisation, memory model diff --git a/src/doc/rust.css b/src/doc/rust.css index cd15828318..6204f38a37 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -221,6 +221,10 @@ a > code { color: #428BCA; } +.section-header > a > code { + color: #8D1A38; +} + /* Code highlighting */ pre.rust .kw { color: #8959A8; } pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; } diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md index 371420431e..2d9356fc42 100644 --- a/src/doc/style/features/traits/generics.md +++ b/src/doc/style/features/traits/generics.md @@ -29,7 +29,7 @@ explicitly implement to be used by this generic function. explicit conversions or other method calls would usually be necessary. See the [overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions) below. -* _Precise types_. Because generic give a _name_ to the specific type +* _Precise types_. Because generics give a _name_ to the specific type implementing a trait, it is possible to be precise about places where that exact type is required or produced. For example, a function diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index ca3381ffba..24686e772e 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -16,6 +16,7 @@ * [Iterators](iterators.md) * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) + * [Choosing your Guarantees](choosing-your-guarantees.md) * [FFI](ffi.md) * [Borrow and AsRef](borrow-and-asref.md) * [Release Channels](release-channels.md) @@ -25,8 +26,7 @@ * [Primitive Types](primitive-types.md) * [Comments](comments.md) * [if](if.md) - * [for loops](for-loops.md) - * [while loops](while-loops.md) + * [Loops](loops.md) * [Ownership](ownership.md) * [References and Borrowing](references-and-borrowing.md) * [Lifetimes](lifetimes.md) @@ -63,7 +63,7 @@ * [No stdlib](no-stdlib.md) * [Intrinsics](intrinsics.md) * [Lang items](lang-items.md) - * [Link args](link-args.md) + * [Advanced linking](advanced-linking.md) * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) * [Slice Patterns](slice-patterns.md) diff --git a/src/doc/trpl/academic-research.md b/src/doc/trpl/academic-research.md index f4f066fb3d..e317f67934 100644 --- a/src/doc/trpl/academic-research.md +++ b/src/doc/trpl/academic-research.md @@ -12,7 +12,7 @@ Recommended for inspiration and a better understanding of Rust's background. * [Macros that work together](https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf) * [Traits: composable units of behavior](http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf) * [Alias burying](http://www.cs.uwm.edu/faculty/boyland/papers/unique-preprint.ps) - We tried something similar and abandoned it. -* [External uniqueness is unique enough](http://www.computingscience.nl/research/techreps/repo/CS-2002/2002-048.pdf) +* [External uniqueness is unique enough](http://www.cs.uu.nl/research/techreps/UU-CS-2002-048.html) * [Uniqueness and Reference Immutability for Safe Parallelism](https://research.microsoft.com/pubs/170528/msr-tr-2012-79.pdf) * [Region Based Memory Management](http://www.cs.ucla.edu/~palsberg/tba/papers/tofte-talpin-iandc97.pdf) @@ -26,10 +26,10 @@ Recommended for inspiration and a better understanding of Rust's background. * [Dynamic circular work stealing deque](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.170.1097&rep=rep1&type=pdf) - The Chase/Lev deque * [Work-first and help-first scheduling policies for async-finish task parallelism](http://www.cs.rice.edu/%7Eyguo/pubs/PID824943.pdf) - More general than fully-strict work stealing * [A Java fork/join calamity](http://www.coopsoft.com/ar/CalamityArticle.html) - critique of Java's fork/join library, particularly its application of work stealing to non-strict computation -* [Scheduling techniques for concurrent systems](http://www.ece.rutgers.edu/%7Eparashar/Classes/ece572-papers/05/ps-ousterhout.pdf) +* [Scheduling techniques for concurrent systems](http://www.stanford.edu/~ouster/cgi-bin/papers/coscheduling.pdf) * [Contention aware scheduling](http://www.blagodurov.net/files/a8-blagodurov.pdf) * [Balanced work stealing for time-sharing multicores](http://www.cse.ohio-state.edu/hpcs/WWW/HTML/publications/papers/TR-12-1.pdf) -* [Three layer cake](http://www.upcrc.illinois.edu/workshops/paraplop10/papers/paraplop10_submission_8.pdf) +* [Three layer cake for shared-memory programming](http://dl.acm.org/citation.cfm?id=1953616&dl=ACM&coll=DL&CFID=524387192&CFTOKEN=44362705) * [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf) * [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf) * [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf) @@ -42,5 +42,32 @@ Recommended for inspiration and a better understanding of Rust's background. ### Papers *about* Rust -* [GPU programming in Rust](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf) -* [Parallel closures: a new twist on an old idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) - not exactly about rust, but by nmatsakis +* [GPU Programming in Rust: Implementing High Level Abstractions in a +Systems Level +Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work by Eric Holk. +* [Parallel closures: a new twist on an old + idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea) + - not exactly about rust, but by nmatsakis +* [Patina: A Formalization of the Rust Programming + Language](ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf). Early + formalization of a subset of the type system, by Eric Reed. +* [Experience Report: Developing the Servo Web Browser Engine using + Rust](http://arxiv.org/abs/1505.07383). By Lars Bergstrom. +* [Implementing a Generic Radix Trie in + Rust](https://michaelsproul.github.io/rust_radix_paper/rust-radix-sproul.pdf). Undergrad + paper by Michael Sproul. +* [Reenix: Implementing a Unix-Like Operating System in + Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex + Light. +* [Evaluation of performance and productivity metrics of potential + programming languages in the HPC environment](). Bachelor's thesis by + Florian Wilkens. Compares C, Go and Rust. +* [Nom, a byte oriented, streaming, zero copy, parser combinators library + in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By + Geoffroy Couprie, research for VLC. +* [Graph-Based Higher-Order Intermediate + Representation](http://compilers.cs.uni-saarland.de/papers/lkh15_cgo.pdf). An + experimental IR implemented in Impala, a Rust-like language. +* [Code Refinement of Stencil + Codes](http://compilers.cs.uni-saarland.de/papers/ppl14_web.pdf). Another + paper using Impala. diff --git a/src/doc/trpl/advanced-linking.md b/src/doc/trpl/advanced-linking.md new file mode 100644 index 0000000000..6d37043354 --- /dev/null +++ b/src/doc/trpl/advanced-linking.md @@ -0,0 +1,151 @@ +% Advanced Linking + +The common cases of linking with Rust have been covered earlier in this book, +but supporting the range of linking possibilities made available by other +languages is important for Rust to achieve seamless interaction with native +libraries. + +# Link args + +There is one other way to tell `rustc` how to customize linking, and that is via +the `link_args` attribute. This attribute is applied to `extern` blocks and +specifies raw flags which need to get passed to the linker when producing an +artifact. An example usage would be: + +``` no_run +#![feature(link_args)] + +#[link_args = "-foo -bar -baz"] +extern {} +# fn main() {} +``` + +Note that this feature is currently hidden behind the `feature(link_args)` gate +because this is not a sanctioned way of performing linking. Right now `rustc` +shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), +so it makes sense to provide extra command line +arguments, but this will not always be the case. In the future `rustc` may use +LLVM directly to link native libraries, in which case `link_args` will have no +meaning. You can achieve the same effect as the `link-args` attribute with the +`-C link-args` argument to `rustc`. + +It is highly recommended to *not* use this attribute, and rather use the more +formal `#[link(...)]` attribute on `extern` blocks instead. + +# Static linking + +Static linking refers to the process of creating output that contain all +required libraries and so don't need libraries installed on every system where +you want to use your compiled project. Pure-Rust dependencies are statically +linked by default so you can use created binaries and libraries without +installing the Rust everywhere. By contrast, native libraries +(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to +change this and statically link them as well. + +Linking is a very platform dependent topic — on some platforms, static linking +may not be possible at all! This section assumes some basic familiarity with +linking on your platform of choice. + +## Linux + +By default, all Rust programs on Linux will link to the system `libc` along with +a number of other libraries. Let's look at an example on a 64-bit Linux machine +with GCC and `glibc` (by far the most common `libc` on Linux): + +``` text +$ cat example.rs +fn main() {} +$ rustc example.rs +$ ldd example + linux-vdso.so.1 => (0x00007ffd565fd000) + libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000) + libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000) + librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000) + libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000) + libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000) + /lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000) + libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000) +``` + +Dynamic linking on Linux can be undesirable if you wish to use new library +features on old systems or target systems which do not have the required +dependencies for your program to run. + +Static linking is supported via an alternative `libc`, `musl` - this must be +enabled at Rust compile-time with some prerequisites available. You can compile +your own version of Rust with `musl` enabled and install it into a custom +directory with the instructions below: + +```text +$ mkdir musldist +$ PREFIX=$(pwd)/musldist +$ +$ # Build musl +$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz +[...] +$ tar xf musl-1.1.10.tar.gz +$ cd musl-1.1.10/ +musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX +[...] +musl-1.1.10 $ make +[...] +musl-1.1.10 $ make install +[...] +musl-1.1.10 $ cd .. +$ du -h musldist/lib/libc.a +2.2M musldist/lib/libc.a +$ +$ # Build libunwind.a +$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz +$ tar xf llvm-3.6.1.src.tar.xz +$ cd llvm-3.6.1.src/projects/ +llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi +llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind +llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt +llvm-3.6.1.src/projects $ mkdir libunwind/build +llvm-3.6.1.src/projects $ cd libunwind/build +llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 .. +llvm-3.6.1.src/projects/libunwind/build $ make +llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/ +llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../ +$ du -h musldist/lib/libunwind.a +164K musldist/lib/libunwind.a +$ +$ # Build musl-enabled rust +$ git clone https://github.com/rust-lang/rust.git muslrust +$ cd muslrust +muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX +muslrust $ make +muslrust $ make install +muslrust $ cd .. +$ du -h musldist/bin/rustc +12K musldist/bin/rustc +``` + +You now have a build of a `musl`-enabled Rust! Because we've installed it to a +custom prefix we need to make sure our system can the binaries and appropriate +libraries when we try and run it: + +```text +$ export PATH=$PREFIX/bin:$PATH +$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH +``` + +Let's try it out! + +```text +$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs +$ rustc --target=x86_64-unknown-linux-musl example.rs +$ ldd example + not a dynamic executable +$ ./example +hi! +thread '
' panicked at 'failed', example.rs:1 +``` + +Success! This binary can be copied to almost any Linux machine with the same +machine architecture and run without issues. + +`cargo build` also permits the `--target` option so you should be able to build +your crates as normal. However, you may need to recompile your native libraries +against `musl` before they can be linked against. diff --git a/src/doc/trpl/choosing-your-guarantees.md b/src/doc/trpl/choosing-your-guarantees.md new file mode 100644 index 0000000000..68812f342f --- /dev/null +++ b/src/doc/trpl/choosing-your-guarantees.md @@ -0,0 +1,359 @@ +% Choosing your Guarantees + +One important feature of Rust as language is that it lets us control the costs and guarantees +of a program. + +There are various “wrapper type” abstractions in the Rust standard library which embody +a multitude of tradeoffs between cost, ergonomics, and guarantees. Many let one choose between +run time and compile time enforcement. This section will explain a few selected abstractions in +detail. + +Before proceeding, it is highly recommended that one reads about [ownership][ownership] and +[borrowing][borrowing] in Rust. + +[ownership]: ownership.html +[borrowing]: references-and-borrowing.html + +# Basic pointer types + +## `Box` + +[`Box`][box] is pointer which is “owned”, or a “box”. While it can hand +out references to the contained data, it is the only owner of the data. In particular, when +something like the following occurs: + +```rust +let x = Box::new(1); +let y = x; +// x no longer accessible here +``` + +Here, the box was _moved_ into `y`. As `x` no longer owns it, the compiler will no longer allow the +programmer to use `x` after this. A box can similarly be moved _out_ of a function by returning it. + +When a box (that hasn't been moved) goes out of scope, destructors are run. These destructors take +care of deallocating the inner data. + +This is a zero-cost abstraction for dynamic allocation. If you want to allocate some memory on the +heap and safely pass around a pointer to that memory, this is ideal. Note that you will only be +allowed to share references to this by the regular borrowing rules, checked at compile time. + +[box]: ../std/boxed/struct.Box.html + +## `&T` and `&mut T` + +These are immutable and mutable references respectively. They follow the “read-write lock” +pattern, such that one may either have only one mutable reference to some data, or any number of +immutable ones, but not both. This guarantee is enforced at compile time, and has no visible cost at +runtime. In most cases these two pointer types suffice for sharing cheap references between sections +of code. + +These pointers cannot be copied in such a way that they outlive the lifetime associated with them. + +## `*const T` and `*mut T` + +These are C-like raw pointers with no lifetime or ownership attached to them. They just point to +some location in memory with no other restrictions. The only guarantee that these provide is that +they cannot be dereferenced except in code marked `unsafe`. + +These are useful when building safe, low cost abstractions like `Vec`, but should be avoided in +safe code. + +## `Rc` + +This is the first wrapper we will cover that has a runtime cost. + +[`Rc`][rc] is a reference counted pointer. In other words, this lets us have multiple "owning" +pointers to the same data, and the data will be dropped (destructors will be run) when all pointers +are out of scope. + +Internally, it contains a shared “reference count” (also called “refcount”), +which is incremented each time the `Rc` is cloned, and decremented each time one of the `Rc`s goes +out of scope. The main responsibility of `Rc` is to ensure that destructors are called for shared +data. + +The internal data here is immutable, and if a cycle of references is created, the data will be +leaked. If we want data that doesn't leak when there are cycles, we need a garbage collector. + +#### Guarantees + +The main guarantee provided here is that the data will not be destroyed until all references to it +are out of scope. + +This should be used when we wish to dynamically allocate and share some data (read-only) between +various portions of your program, where it is not certain which portion will finish using the pointer +last. It's a viable alternative to `&T` when `&T` is either impossible to statically check for +correctness, or creates extremely unergonomic code where the programmer does not wish to spend the +development cost of working with. + +This pointer is _not_ thread safe, and Rust will not let it be sent or shared with other threads. +This lets one avoid the cost of atomics in situations where they are unnecessary. + +There is a sister smart pointer to this one, `Weak`. This is a non-owning, but also non-borrowed, +smart pointer. It is also similar to `&T`, but it is not restricted in lifetime—a `Weak` +can be held on to forever. However, it is possible that an attempt to access the inner data may fail +and return `None`, since this can outlive the owned `Rc`s. This is useful for cyclic +data structures and other things. + +#### Cost + +As far as memory goes, `Rc` is a single allocation, though it will allocate two extra words (i.e. +two `usize` values) as compared to a regular `Box` (for "strong" and "weak" refcounts). + +`Rc` has the computational cost of incrementing/decrementing the refcount whenever it is cloned +or goes out of scope respectively. Note that a clone will not do a deep copy, rather it will simply +increment the inner reference count and return a copy of the `Rc`. + +[rc]: ../std/rc/struct.Rc.html + +# Cell types + +`Cell`s provide interior mutability. In other words, they contain data which can be manipulated even +if the type cannot be obtained in a mutable form (for example, when it is behind an `&`-ptr or +`Rc`). + +[The documentation for the `cell` module has a pretty good explanation for these][cell-mod]. + +These types are _generally_ found in struct fields, but they may be found elsewhere too. + +## `Cell` + +[`Cell`][cell] is a type that provides zero-cost interior mutability, but only for `Copy` types. +Since the compiler knows that all the data owned by the contained value is on the stack, there's +no worry of leaking any data behind references (or worse!) by simply replacing the data. + +It is still possible to violate your own invariants using this wrapper, so be careful when using it. +If a field is wrapped in `Cell`, it's a nice indicator that the chunk of data is mutable and may not +stay the same between the time you first read it and when you intend to use it. + +```rust +use std::cell::Cell; + +let x = Cell::new(1); +let y = &x; +let z = &x; +x.set(2); +y.set(3); +z.set(4); +println!("{}", x.get()); +``` + +Note that here we were able to mutate the same value from various immutable references. + +This has the same runtime cost as the following: + +```rust,ignore +let mut x = 1; +let y = &mut x; +let z = &mut x; +x = 2; +*y = 3; +*z = 4; +println!("{}", x); +``` + +but it has the added benefit of actually compiling successfully. + +#### Guarantees + +This relaxes the “no aliasing with mutability” restriction in places where it's +unnecessary. However, this also relaxes the guarantees that the restriction provides; so if your +invariants depend on data stored within `Cell`, you should be careful. + +This is useful for mutating primitives and other `Copy` types when there is no easy way of +doing it in line with the static rules of `&` and `&mut`. + +`Cell` does not let you obtain interior references to the data, which makes it safe to freely +mutate. + +#### Cost + +There is no runtime cost to using `Cell`, however if you are using it to wrap larger (`Copy`) +structs, it might be worthwhile to instead wrap individual fields in `Cell` since each write is +otherwise a full copy of the struct. + + +## `RefCell` + +[`RefCell`][refcell] also provides interior mutability, but isn't restricted to `Copy` types. + +Instead, it has a runtime cost. `RefCell` enforces the read-write lock pattern at runtime (it's +like a single-threaded mutex), unlike `&T`/`&mut T` which do so at compile time. This is done by the +`borrow()` and `borrow_mut()` functions, which modify an internal reference count and return smart +pointers which can be dereferenced immutably and mutably respectively. The refcount is restored when +the smart pointers go out of scope. With this system, we can dynamically ensure that there are never +any other borrows active when a mutable borrow is active. If the programmer attempts to make such a +borrow, the thread will panic. + +```rust +use std::cell::RefCell; + +let x = RefCell::new(vec![1,2,3,4]); +{ + println!("{:?}", *x.borrow()) +} + +{ + let mut my_ref = x.borrow_mut(); + my_ref.push(1); +} +``` + +Similar to `Cell`, this is mainly useful for situations where it's hard or impossible to satisfy the +borrow checker. Generally we know that such mutations won't happen in a nested form, but it's good +to check. + +For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things +simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals +are inside this wrapper. These are only modified once (during creation, which is not right after +initialization) or a couple of times in well-separated places. However, since this struct is +pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps +impossible) and probably form a soup of `&`-ptrs which would be hard to extend. On the other hand, +the `RefCell` provides a cheap (not zero-cost) way of safely accessing these. In the future, if +someone adds some code that attempts to modify the cell when it's already borrowed, it will cause a +(usually deterministic) panic which can be traced back to the offending borrow. + +Similarly, in Servo's DOM there is a lot of mutation, most of which is local to a DOM type, but some +of which crisscrosses the DOM and modifies various things. Using `RefCell` and `Cell` to guard all +mutation lets us avoid worrying about mutability everywhere, and it simultaneously highlights the +places where mutation is _actually_ happening. + +Note that `RefCell` should be avoided if a mostly simple solution is possible with `&` pointers. + +#### Guarantees + +`RefCell` relaxes the _static_ restrictions preventing aliased mutation, and replaces them with +_dynamic_ ones. As such the guarantees have not changed. + +#### Cost + +`RefCell` does not allocate, but it contains an additional "borrow state" +indicator (one word in size) along with the data. + +At runtime each borrow causes a modification/check of the refcount. + +[cell-mod]: ../std/cell/ +[cell]: ../std/cell/struct.Cell.html +[refcell]: ../std/cell/struct.RefCell.html +[ctxt]: ../rustc/middle/ty/struct.ctxt.html + +# Synchronous types + +Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc` and +`RefCell`, which both use non-atomic reference counts (_atomic_ reference counts are those which +can be incremented from multiple threads without causing a data race), cannot be used this way. This +makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of +`Arc` and `Mutex`/`RWLock` + +Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile +time. + +There are many useful wrappers for concurrent programming in the [sync][sync] module, but only the +major ones will be covered below. + +[sync]: ../std/sync/index.html + +## `Arc` + +[`Arc`][arc] is just a version of `Rc` that uses an atomic reference count (hence, "Arc"). +This can be sent freely between threads. + +C++'s `shared_ptr` is similar to `Arc`, however in the case of C++ the inner data is always mutable. +For semantics similar to that from C++, we should use `Arc>`, `Arc>`, or +`Arc>`[^4] (`UnsafeCell` is a cell type that can be used to hold any data and has +no runtime cost, but accessing it requires `unsafe` blocks). The last one should only be used if we +are certain that the usage won't cause any memory unsafety. Remember that writing to a struct is not +an atomic operation, and many functions like `vec.push()` can reallocate internally and cause unsafe +behavior, so even monotonicity may not be enough to justify `UnsafeCell`. + +[^4]: `Arc>` actually won't compile since `UnsafeCell` isn't `Send` or `Sync`, but we can wrap it in a type and implement `Send`/`Sync` for it manually to get `Arc>` where `Wrapper` is `struct Wrapper(UnsafeCell)`. + +#### Guarantees + +Like `Rc`, this provides the (thread safe) guarantee that the destructor for the internal data will +be run when the last `Arc` goes out of scope (barring any cycles). + +#### Cost + +This has the added cost of using atomics for changing the refcount (which will happen whenever it is +cloned or goes out of scope). When sharing data from an `Arc` in a single thread, it is preferable +to share `&` pointers whenever possible. + +[arc]: ../std/sync/struct.Arc.html + +## `Mutex` and `RwLock` + +[`Mutex`][mutex] and [`RwLock`][rwlock] provide mutual-exclusion via RAII guards (guards are +objects which maintain some state, like a lock, until their destructor is called). For both of +these, the mutex is opaque until we call `lock()` on it, at which point the thread will block +until a lock can be acquired, and then a guard will be returned. This guard can be used to access +the inner data (mutably), and the lock will be released when the guard goes out of scope. + +```rust,ignore +{ + let guard = mutex.lock(); + // guard dereferences mutably to the inner type + *guard += 1; +} // lock released when destructor runs +``` + + +`RwLock` has the added benefit of being efficient for multiple reads. It is always safe to have +multiple readers to shared data as long as there are no writers; and `RwLock` lets readers acquire a +"read lock". Such locks can be acquired concurrently and are kept track of via a reference count. +Writers must obtain a "write lock" which can only be obtained when all readers have gone out of +scope. + +#### Guarantees + +Both of these provide safe shared mutability across threads, however they are prone to deadlocks. +Some level of additional protocol safety can be obtained via the type system. + +#### Costs + +These use internal atomic-like types to maintain the locks, which are pretty costly (they can block +all memory reads across processors till they're done). Waiting on these locks can also be slow when +there's a lot of concurrent access happening. + +[rwlock]: ../std/sync/struct.RwLock.html +[mutex]: ../std/sync/struct.Mutex.html +[sessions]: https://github.com/Munksgaard/rust-sessions + +# Composition + +A common gripe when reading Rust code is with types like `Rc>>` (or even more more +complicated compositions of such types). It's not always clear what the composition does, or why the +author chose one like this (and when one should be using such a composition in one's own code) + +Usually, it's a case of composing together the guarantees that you need, without paying for stuff +that is unnecessary. + +For example, `Rc>` is one such composition. `Rc` itself can't be dereferenced mutably; +because `Rc` provides sharing and shared mutability can lead to unsafe behavior, so we put +`RefCell` inside to get dynamically verified shared mutability. Now we have shared mutable data, +but it's shared in a way that there can only be one mutator (and no readers) or multiple readers. + +Now, we can take this a step further, and have `Rc>>` or `Rc>>`. These +are both shareable, mutable vectors, but they're not the same. + +With the former, the `RefCell` is wrapping the `Vec`, so the `Vec` in its entirety is +mutable. At the same time, there can only be one mutable borrow of the whole `Vec` at a given time. +This means that your code cannot simultaneously work on different elements of the vector from +different `Rc` handles. However, we are able to push and pop from the `Vec` at will. This is +similar to an `&mut Vec` with the borrow checking done at runtime. + +With the latter, the borrowing is of individual elements, but the overall vector is immutable. Thus, +we can independently borrow separate elements, but we cannot push or pop from the vector. This is +similar to an `&mut [T]`[^3], but, again, the borrow checking is at runtime. + +In concurrent programs, we have a similar situation with `Arc>`, which provides shared +mutability and ownership. + +When reading code that uses these, go in step by step and look at the guarantees/costs provided. + +When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at +which point of the composition we need them. For example, if there is a choice between +`Vec>` and `RefCell>`, we should figure out the tradeoffs as done above and pick +one. + +[^3]: `&[T]` and `&mut [T]` are _slices_; they consist of a pointer and a length and can refer to a portion of a vector or array. `&mut [T]` can have its elements mutated, however its length cannot be touched. diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 7687d2a57d..e7eb48dc42 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -38,6 +38,17 @@ fn add_one(x: i32) -> i32 { } ``` +There is another style of doc comment, `//!`, to comment containing items (e.g. +crates, modules or functions), instead of the items following it. Commonly used +inside crates root (lib.rs) or modules root (mod.rs): + +``` +//! # The Rust Standard Library +//! +//! The Rust Standard Library provides the essential runtime +//! functionality for building portable Rust software. +``` + When writing doc comments, providing some examples of usage is very, very helpful. You’ll notice we’ve used a new macro here: `assert_eq!`. This compares two values, and `panic!`s if they’re not equal to each other. It’s very helpful diff --git a/src/doc/trpl/compiler-plugins.md b/src/doc/trpl/compiler-plugins.md index 127e097c34..12adb9050d 100644 --- a/src/doc/trpl/compiler-plugins.md +++ b/src/doc/trpl/compiler-plugins.md @@ -61,7 +61,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) ("I", 1)]; let text = match args { - [TtToken(_, token::Ident(s, _))] => token::get_ident(s).to_string(), + [TtToken(_, token::Ident(s, _))] => s.to_string(), _ => { cx.span_err(sp, "argument should be a single identifier"); return DummyResult::any(sp); @@ -186,8 +186,7 @@ impl LintPass for Pass { } fn check_item(&mut self, cx: &Context, it: &ast::Item) { - let name = token::get_ident(it.ident); - if name.get() == "lintme" { + if it.ident.name == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index ccd769089d..5a9569a69e 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -10,11 +10,12 @@ system is up to the task, and gives you powerful ways to reason about concurrent code at compile time. Before we talk about the concurrency features that come with Rust, it's important -to understand something: Rust is low-level enough that all of this is provided -by the standard library, not by the language. This means that if you don't like -some aspect of the way Rust handles concurrency, you can implement an alternative -way of doing things. [mio](https://github.com/carllerche/mio) is a real-world -example of this principle in action. +to understand something: Rust is low-level enough that the vast majority of +this is provided by the standard library, not by the language. This means that +if you don't like some aspect of the way Rust handles concurrency, you can +implement an alternative way of doing things. +[mio](https://github.com/carllerche/mio) is a real-world example of this +principle in action. ## Background: `Send` and `Sync` @@ -114,7 +115,7 @@ languages. It will not compile: use std::thread; fn main() { - let mut data = vec![1u32, 2, 3]; + let mut data = vec![1, 2, 3]; for i in 0..3 { thread::spawn(move || { @@ -152,7 +153,7 @@ use std::thread; use std::sync::Mutex; fn main() { - let mut data = Mutex::new(vec![1u32, 2, 3]); + let mut data = Mutex::new(vec![1, 2, 3]); for i in 0..3 { let data = data.lock().unwrap(); @@ -194,7 +195,7 @@ use std::sync::{Arc, Mutex}; use std::thread; fn main() { - let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); + let data = Arc::new(Mutex::new(vec![1, 2, 3])); for i in 0..3 { let data = data.clone(); @@ -216,7 +217,7 @@ thread more closely: # use std::sync::{Arc, Mutex}; # use std::thread; # fn main() { -# let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); +# let data = Arc::new(Mutex::new(vec![1, 2, 3])); # for i in 0..3 { # let data = data.clone(); thread::spawn(move || { @@ -254,7 +255,7 @@ use std::thread; use std::sync::mpsc; fn main() { - let data = Arc::new(Mutex::new(0u32)); + let data = Arc::new(Mutex::new(0)); let (tx, rx) = mpsc::channel(); @@ -292,7 +293,7 @@ fn main() { let tx = tx.clone(); thread::spawn(move || { - let answer = 42u32; + let answer = 42; tx.send(answer); }); diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index 63fdef0760..6989099206 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -355,6 +355,10 @@ Hello in English: Hello! Goodbye in English: Goodbye. ``` +`pub` also applies to `struct`s and their member fields. In keeping with Rust’s +tendency toward safety, simply making a `struct` public won't automatically +make its members public: you must mark the fields individually with `pub`. + Now that our functions are public, we can use them. Great! However, typing out `phrases::english::greetings::hello()` is very long and repetitive. Rust has another keyword for importing names into the current scope, so that you can @@ -517,9 +521,6 @@ of `foo` relative to where we are. If that’s prefixed with `::`, as in `::foo::bar()`, it refers to a different `foo`, an absolute path from your crate root. -Also, note that we `pub use`d before we declared our `mod`s. Rust requires that -`use` declarations go first. - This will build and run: ```bash diff --git a/src/doc/trpl/dining-philosophers.md b/src/doc/trpl/dining-philosophers.md index b24d50c890..9539cd3447 100644 --- a/src/doc/trpl/dining-philosophers.md +++ b/src/doc/trpl/dining-philosophers.md @@ -151,7 +151,7 @@ look at `main()` again: # struct Philosopher { # name: String, # } -# +# # impl Philosopher { # fn new(name: &str) -> Philosopher { # Philosopher { @@ -159,7 +159,7 @@ look at `main()` again: # } # } # } -# +# fn main() { let p1 = Philosopher::new("Judith Butler"); let p2 = Philosopher::new("Gilles Deleuze"); @@ -197,15 +197,15 @@ a method, and then loop through all the philosophers, calling it: ```rust struct Philosopher { name: String, -} +} -impl Philosopher { +impl Philosopher { fn new(name: &str) -> Philosopher { Philosopher { name: name.to_string(), } } - + fn eat(&self) { println!("{} is done eating.", self.name); } @@ -267,15 +267,15 @@ use std::thread; struct Philosopher { name: String, -} +} -impl Philosopher { +impl Philosopher { fn new(name: &str) -> Philosopher { Philosopher { name: name.to_string(), } } - + fn eat(&self) { println!("{} is eating.", self.name); @@ -348,9 +348,9 @@ use std::thread; struct Philosopher { name: String, -} +} -impl Philosopher { +impl Philosopher { fn new(name: &str) -> Philosopher { Philosopher { name: name.to_string(), @@ -401,7 +401,7 @@ let handles: Vec<_> = philosophers.into_iter().map(|p| { While this is only five lines, they’re a dense five. Let’s break it down. ```rust,ignore -let handles: Vec<_> = +let handles: Vec<_> = ``` We introduce a new binding, called `handles`. We’ve given it this name because @@ -460,15 +460,15 @@ If you run this program, you’ll see that the philosophers eat out of order! We have multi-threading! ```text +Judith Butler is eating. Gilles Deleuze is eating. -Gilles Deleuze is done eating. +Karl Marx is eating. Emma Goldman is eating. -Emma Goldman is done eating. Michel Foucault is eating. -Judith Butler is eating. Judith Butler is done eating. -Karl Marx is eating. +Gilles Deleuze is done eating. Karl Marx is done eating. +Emma Goldman is done eating. Michel Foucault is done eating. ``` diff --git a/src/doc/trpl/documentation.md b/src/doc/trpl/documentation.md index 1a64ab6646..01b53a6c49 100644 --- a/src/doc/trpl/documentation.md +++ b/src/doc/trpl/documentation.md @@ -33,8 +33,10 @@ pub fn new(value: T) -> Rc { ``` This code generates documentation that looks [like this][rc-new]. I've left the -implementation out, with a regular comment in its place. That's the first thing -to notice about this annotation: it uses `///`, instead of `//`. The triple slash +implementation out, with a regular comment in its place. + +The first thing to notice about this annotation is that it uses +`///` instead of `//`. The triple slash indicates a documentation comment. Documentation comments are written in Markdown. @@ -102,7 +104,7 @@ we could have added more explanation in a new paragraph. #### Special sections Next, are special sections. These are indicated with a header, `#`. There -are three kinds of headers that are commonly used. They aren't special syntax, +are four kinds of headers that are commonly used. They aren't special syntax, just convention, for now. ```rust @@ -144,7 +146,7 @@ responsible for upholding. # fn foo() {} ``` -Third, `Examples`. Include one or more examples of using your function or +Fourth, `Examples`. Include one or more examples of using your function or method, and your users will love you for it. These examples go inside of code block annotations, which we'll talk about in a moment, and can have more than one section: @@ -375,7 +377,7 @@ $ rustdoc --test path/to/my/crate/root.rs $ cargo test ``` -That's right, `cargo test` tests embedded documentation too. However, +That's right, `cargo test` tests embedded documentation too. However, `cargo test` will not test binary crates, only library ones. This is due to the way `rustdoc` works: it links against the library to be tested, but with a binary, there’s nothing to link to. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 580eaa6ca5..8dd5a3650e 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -50,6 +50,8 @@ is very wrong. Wrong enough that we can't continue with things in the current state. Another example is using the `unreachable!()` macro: ```rust,ignore +use Event::NewRelease; + enum Event { NewRelease, } @@ -71,7 +73,7 @@ fn descriptive_probability(event: Event) -> &'static str { } fn main() { - std::io::println(descriptive_probability(NewRelease)); + println!("{}", descriptive_probability(NewRelease)); } ``` diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 917d8dbe19..753a5a32e8 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -309,8 +309,8 @@ and invokes callbacks from there. In these cases access to Rust data structures inside the callbacks is especially unsafe and proper synchronization mechanisms must be used. Besides classical synchronization mechanisms like mutexes, one possibility in -Rust is to use channels (in `std::comm`) to forward data from the C thread -that invoked the callback into a Rust thread. +Rust is to use channels (in `std::sync::mpsc`) to forward data from the C +thread that invoked the callback into a Rust thread. If an asynchronous callback targets a special object in the Rust address space it is also absolutely necessary that no more callbacks are performed by the @@ -340,7 +340,7 @@ libraries: Note that frameworks are only available on OSX targets. The different `kind` values are meant to differentiate how the native library -participates in linkage. From a linkage perspective, the rust compiler creates +participates in linkage. From a linkage perspective, the Rust compiler creates two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary). Native dynamic library and framework dependencies are propagated to the final artifact boundary, while static library dependencies are not propagated at @@ -350,9 +350,9 @@ artifact. A few examples of how this model can be used are: * A native build dependency. Sometimes some C/C++ glue is needed when writing - some rust code, but distribution of the C/C++ code in a library format is just + some Rust code, but distribution of the C/C++ code in a library format is just a burden. In this case, the code will be archived into `libfoo.a` and then the - rust crate would declare a dependency via `#[link(name = "foo", kind = + Rust crate would declare a dependency via `#[link(name = "foo", kind = "static")]`. Regardless of the flavor of output for the crate, the native static library @@ -361,7 +361,7 @@ A few examples of how this model can be used are: * A normal dynamic dependency. Common system libraries (like `readline`) are available on a large number of systems, and often a static copy of these - libraries cannot be found. When this dependency is included in a rust crate, + libraries cannot be found. When this dependency is included in a Rust crate, partial targets (like rlibs) will not link to the library, but when the rlib is included in a final target (like a binary), the native library will be linked in. @@ -533,19 +533,10 @@ attribute turns off Rust's name mangling, so that it is easier to link to. # FFI and panics -It’s important to be mindful of `panic!`s when working with FFI. This code, -when called from C, will `abort`: - -```rust -#[no_mangle] -pub extern fn oh_no() -> ! { - panic!("Oops!"); -} -# fn main() {} -``` - -If you’re writing code that may panic, you should run it in another thread, -so that the panic doesn’t bubble up to C: +It’s important to be mindful of `panic!`s when working with FFI. A `panic!` +across an FFI boundary is undefined behavior. If you’re writing code that may +panic, you should run it in another thread, so that the panic doesn’t bubble up +to C: ```rust use std::thread; diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md deleted file mode 100644 index 2866cee3a1..0000000000 --- a/src/doc/trpl/for-loops.md +++ /dev/null @@ -1,85 +0,0 @@ -% for Loops - -The `for` loop is used to loop a particular number of times. Rust’s `for` loops -work a bit differently than in other systems languages, however. Rust’s `for` -loop doesn’t look like this “C-style” `for` loop: - -```c -for (x = 0; x < 10; x++) { - printf( "%d\n", x ); -} -``` - -Instead, it looks like this: - -```rust -for x in 0..10 { - println!("{}", x); // x: i32 -} -``` - -In slightly more abstract terms, - -```ignore -for var in expression { - code -} -``` - -The expression is an [iterator][iterator]. The iterator gives back a series of -elements. Each element is one iteration of the loop. That value is then bound -to the name `var`, which is valid for the loop body. Once the body is over, the -next value is fetched from the iterator, and we loop another time. When there -are no more values, the `for` loop is over. - -[iterator]: iterators.html - -In our example, `0..10` is an expression that takes a start and an end position, -and gives an iterator over those values. The upper bound is exclusive, though, -so our loop will print `0` through `9`, not `10`. - -Rust does not have the “C-style” `for` loop on purpose. Manually controlling -each element of the loop is complicated and error prone, even for experienced C -developers. - -# Enumerate - -When you need to keep track of how many times you already looped, you can use the `.enumerate()` function. - -## On ranges: - -```rust -for (i,j) in (5..10).enumerate() { - println!("i = {} and j = {}", i, j); -} -``` - -Outputs: - -```text -i = 0 and j = 5 -i = 1 and j = 6 -i = 2 and j = 7 -i = 3 and j = 8 -i = 4 and j = 9 -``` - -Don't forget to add the parentheses around the range. - -## On iterators: - -```rust -# let lines = "hello\nworld".lines(); -for (linenumber, line) in lines.enumerate() { - println!("{}: {}", linenumber, line); -} -``` - -Outputs: - -```text -0: Content of line one -1: Content of line two -2: Content of line tree -3: Content of line four -``` diff --git a/src/doc/trpl/glossary.md b/src/doc/trpl/glossary.md index c97da0e95b..307aef8018 100644 --- a/src/doc/trpl/glossary.md +++ b/src/doc/trpl/glossary.md @@ -3,24 +3,12 @@ Not every Rustacean has a background in systems programming, nor in computer science, so we've added explanations of terms that might be unfamiliar. -### Arity - -Arity refers to the number of arguments a function or operation takes. - -```rust -let x = (2, 3); -let y = (4, 6); -let z = (8, 2, 6); -``` - -In the example above `x` and `y` have arity 2. `z` has arity 3. - ### Abstract Syntax Tree -When a compiler is compiling your program, it does a number of different -things. One of the things that it does is turn the text of your program into an -‘abstract syntax tree’, or ‘AST’. This tree is a representation of the -structure of your program. For example, `2 + 3` can be turned into a tree: +When a compiler is compiling your program, it does a number of different things. +One of the things that it does is turn the text of your program into an +‘abstract syntax tree’, or ‘AST’. This tree is a representation of the structure +of your program. For example, `2 + 3` can be turned into a tree: ```text + @@ -37,3 +25,41 @@ And `2 + (3 * 4)` would look like this: / \ 3 4 ``` + +### Arity + +Arity refers to the number of arguments a function or operation takes. + +```rust +let x = (2, 3); +let y = (4, 6); +let z = (8, 2, 6); +``` + +In the example above `x` and `y` have arity 2. `z` has arity 3. + +### Expression + +In computer programming, an expression is a combination of values, constants, +variables, operators and functions that evaluate to a single value. For example, +`2 + (3 * 4)` is an expression that returns the value 14. It is worth noting +that expressions can have side-effects. For example, a function included in an +expression might perform actions other than simply returning a value. + +### Expression-Oriented Language + +In early programming languages, [expressions][expression] and +[statements][statement] were two separate syntactic categories: expressions had +a value and statements did things. However, later languages blurred this +distinction, allowing expressions to do things and statements to have a value. +In an expression-oriented language, (nearly) every statement is an expression +and therefore returns a value. Consequently, these expression statements can +themselves form part of larger expressions. + +[expression]: glossary.html#expression +[statement]: glossary.html#statement + +### Statement + +In computer programming, a statement is the smallest standalone element of a +programming language that commands a computer to perform an action. diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index a599b8a855..63a1c10f84 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -98,8 +98,8 @@ use std::io; We’ll need to take user input, and then print the result as output. As such, we need the `io` library from the standard library. Rust only imports a few things -into every program, [the ‘prelude’][prelude]. If it’s not in the prelude, -you’ll have to `use` it directly. +by default into every program, [the ‘prelude’][prelude]. If it’s not in the +prelude, you’ll have to `use` it directly. [prelude]: ../std/prelude/index.html @@ -360,10 +360,12 @@ rand="0.3.0" The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: everything that follows it is part of it, until the next section starts. Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve used version `0.3.0`. +crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`, +which Cargo understands to be any release that’s compatible with this specific version. Cargo understands [Semantic Versioning][semver], which is a standard for writing version -numbers. If we wanted to use the latest version we could use `*` or we could use a range -of versions. [Cargo’s documentation][cargodoc] contains more details. +numbers. If we wanted to use only `0.3.0` exactly, we could use `=0.3.0`. If we +wanted to use the latest version we could use `*`; We could use a range of +versions. [Cargo’s documentation][cargodoc] contains more details. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html @@ -497,7 +499,7 @@ generator, which is local to the particular [thread][concurrency] of execution we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method available. This method takes two arguments, and generates a number between them. It’s inclusive on the lower bound, but exclusive on the upper bound, -so we need `1` and `101` to get a number between one and a hundred. +so we need `1` and `101` to get a number ranging from one to a hundred. [concurrency]: concurrency.html diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index 8e47997788..4bd7de23f0 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -8,13 +8,13 @@ so it is assumed that Rust projects will use Cargo from the beginning. [cratesio]: http://doc.crates.io Cargo manages three things: building your code, downloading the dependencies -your code needs, and building those dependencies. At first, your -program doesn’t have any dependencies, so we’ll only be using the first part of -its functionality. Eventually, we’ll add more. Since we started off by using -Cargo, it'll be easy to add later. +your code needs, and building those dependencies. At first, your program doesn’t +have any dependencies, so we’ll only be using the first part of its +functionality. Eventually, we’ll add more. Since we started off by using Cargo, +it'll be easy to add later. -If you installed Rust via the official installers you will also have Cargo. If -you installed Rust some other way, you may want to [check the Cargo +If we installed Rust via the official installers we will also have Cargo. If we +installed Rust some other way, we may want to [check the Cargo README][cargoreadme] for specific instructions about installing it. [cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies @@ -23,20 +23,21 @@ README][cargoreadme] for specific instructions about installing it. Let’s convert Hello World to Cargo. -To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` -configuration file, and put our source file in the right place. Let's -do that part first: +To Cargo-ify our project, we need to do three things: Make a `Cargo.toml` +configuration file, put our source file in the right place, and get rid of the +old executable (`main.exe` on Windows, `main` everywhere else). Let's do that part first: ```bash $ mkdir src $ mv main.rs src/main.rs +$ rm main # or main.exe on Windows ``` -Note that since we're creating an executable, we used `main.rs`. If we -want to make a library instead, we should use `lib.rs`. This convention is required -for Cargo to successfully compile our projects, but it can be overridden if we wish. -Custom file locations for the entry point can be specified -with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file. +Note that since we're creating an executable, we retain `main.rs` as the source +filename. If we want to make a library instead, we should use `lib.rs`. This +convention is used by Cargo to successfully compile our projects, but it can be +overridden if we wish. Custom file locations for the entry point can be +specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file. [crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target @@ -63,8 +64,8 @@ version = "0.0.1" authors = [ "Your name " ] ``` -This file is in the [TOML][toml] format. TOML is similar to INI, but has some -extra goodies. According to the TOML docs, +This file is in the [TOML][toml] format. TOML is similar to INI, but has some +extra goodies. According to the TOML docs, > TOML aims to be a minimal configuration file format that's easy to read due > to obvious semantics. TOML is designed to map unambiguously to a hash table. @@ -73,7 +74,8 @@ extra goodies. According to the TOML docs, [toml]: https://github.com/toml-lang/toml -Once you have this file in place, we should be ready to build! To do so, run: +Once we have this file in place in our project's root directory, we should be +ready to build! To do so, run: ```bash $ cargo build diff --git a/src/doc/trpl/hello-world.md b/src/doc/trpl/hello-world.md index eec6fe62f2..cd4326a28d 100644 --- a/src/doc/trpl/hello-world.md +++ b/src/doc/trpl/hello-world.md @@ -111,10 +111,13 @@ string to the screen. Easy enough! [allocation]: the-stack-and-the-heap.html -Finally, the line ends with a semicolon (`;`). Rust is an ‘expression oriented’ -language, which means that most things are expressions, rather than statements. -The `;` is used to indicate that this expression is over, and the next one is -ready to begin. Most lines of Rust code end with a `;`. +Finally, the line ends with a semicolon (`;`). Rust is an [‘expression oriented’ +language][expression-oriented language], which means that most things are +expressions, rather than statements. The `;` is used to indicate that this +expression is over, and the next one is ready to begin. Most lines of Rust code +end with a `;`. + +[expression-oriented language]: glossary.html#expression-oriented-language Finally, actually compiling and running our program. We can compile with our compiler, `rustc`, by passing it the name of our source file: diff --git a/src/doc/trpl/inline-assembly.md b/src/doc/trpl/inline-assembly.md index 4d9166d63b..7659c4ff88 100644 --- a/src/doc/trpl/inline-assembly.md +++ b/src/doc/trpl/inline-assembly.md @@ -103,7 +103,7 @@ fn main() { If you would like to use real operands in this position, however, you are required to put curly braces `{}` around the register that you want, and you are required to put the specific size of the -operand. This is useful for very low level programming, where +operand. This is useful for very low level programming, where which register you use is important: ```rust @@ -166,3 +166,12 @@ unsafe { println!("eax is currently {}", result); # } ``` + +## More Information + +The current implementation of the `asm!` macro is a direct binding to [LLVM's +inline assembler expressions][llvm-docs], so be sure to check out [their +documentation as well][llvm-docs] for more information about clobbers, +constraints, etc. + +[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 44eafd5192..83750ec3b0 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -2,7 +2,7 @@ The first step to using Rust is to install it! There are a number of ways to install Rust, but the easiest is to use the `rustup` script. If you're on Linux -or a Mac, all you need to do is this: +or a Mac, all you need to do is this: > Note: you don't need to type in the `$`s, they just indicate the start of > each command. You’ll see many tutorials and examples around the web that @@ -25,6 +25,12 @@ $ sh rustup.sh [insecurity]: http://curlpipesh.tumblr.com If you're on Windows, please download the appropriate [installer][install-page]. +**NOTE:** By default, the Windows installer will not add Rust to the %PATH% +system variable. If this is the only version of Rust you are installing and you +want to be able to run it from the command line, click on "Advanced" on the +install dialog and on the "Product Features" page ensure "Add to PATH" is +installed on the local hard drive. + [install-page]: http://www.rust-lang.org/install.html @@ -41,6 +47,8 @@ $ sudo /usr/local/lib/rustlib/uninstall.sh If you used the Windows installer, just re-run the `.msi` and it will give you an uninstall option. +## That disclaimer we promised + Some people, and somewhat rightfully so, get very upset when we tell you to `curl | sh`. Basically, when you do this, you are trusting that the good people who maintain Rust aren't going to hack your computer and do bad things. @@ -50,6 +58,8 @@ binary downloads][install-page]. [from-source]: https://github.com/rust-lang/rust#building-from-source +## Platform support + Oh, we should also mention the officially supported platforms: * Windows (7, 8, Server 2008 R2) @@ -66,6 +76,8 @@ integrated as the Linux/OS X experience is. We're working on it! If anything does not work, it is a bug. Please let us know if that happens. Each and every commit is tested against Windows just like any other platform. +## After installation + If you've got Rust installed, you can open up a shell, and type this: ```bash @@ -81,6 +93,11 @@ rustc 1.0.0 (a59de37e9 2015-05-13) If you did, Rust has been installed successfully! Congrats! +If you didn't and you're on Windows, check that Rust is in your %PATH% system +variable. If it isn't, run the installer again, select "Change" on the "Change, +repair, or remove installation" page and ensure "Add to PATH" is installed on +the local hard drive. + This installer also installs a copy of the documentation locally, so you can read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. On Windows, it's in a `share/doc` directory, inside wherever you installed Rust @@ -95,5 +112,5 @@ resources include [the user’s forum][users], and [irc]: irc://irc.mozilla.org/#rust [mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust -[users]: http://users.rust-lang.org/ +[users]: http://users.rust-lang.org/ [stackoverflow]: http://stackoverflow.com/questions/tagged/rust diff --git a/src/doc/trpl/intrinsics.md b/src/doc/trpl/intrinsics.md index e0a8bb59e3..d1d836fe18 100644 --- a/src/doc/trpl/intrinsics.md +++ b/src/doc/trpl/intrinsics.md @@ -11,7 +11,7 @@ perform efficient pointer arithmetic, one would import those functions via a declaration like ```rust -# #![feature(intrinsics)] +#![feature(intrinsics)] # fn main() {} extern "rust-intrinsic" { diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md index 8e7504c2f1..39de8920f0 100644 --- a/src/doc/trpl/lang-items.md +++ b/src/doc/trpl/lang-items.md @@ -54,6 +54,7 @@ fn main(argc: isize, argv: *const *const u8) -> isize { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} ``` Note the use of `abort`: the `exchange_malloc` lang item is assumed to diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 11d651c577..8e02367b92 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -101,6 +101,8 @@ the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut i32` as ‘a mutable reference to an i32’ and `&'a mut i32` as ‘a mutable reference to an `i32` with the lifetime `'a`’. +# In `struct`s + You’ll also need explicit lifetimes when working with [`struct`][structs]s: ```rust @@ -137,6 +139,33 @@ x: &'a i32, uses it. So why do we need a lifetime here? We need to ensure that any reference to a `Foo` cannot outlive the reference to an `i32` it contains. +## `impl` blocks + +Let’s implement a method on `Foo`: + +```rust +struct Foo<'a> { + x: &'a i32, +} + +impl<'a> Foo<'a> { + fn x(&self) -> &'a i32 { self.x } +} + +fn main() { + let y = &5; // this is the same as `let _y = 5; let y = &_y;` + let f = Foo { x: y }; + + println!("x is: {}", f.x()); +} +``` + +As you can see, we need to declare a lifetime for `Foo` in the `impl` line. We repeat +`'a` twice, just like on functions: `impl<'a>` defines a lifetime `'a`, and `Foo<'a>` +uses it. + +## Multiple lifetimes + If you have multiple references, you can use the same lifetime multiple times: ```rust diff --git a/src/doc/trpl/link-args.md b/src/doc/trpl/link-args.md deleted file mode 100644 index ee5159afb8..0000000000 --- a/src/doc/trpl/link-args.md +++ /dev/null @@ -1,25 +0,0 @@ -% Link args - -There is one other way to tell rustc how to customize linking, and that is via -the `link_args` attribute. This attribute is applied to `extern` blocks and -specifies raw flags which need to get passed to the linker when producing an -artifact. An example usage would be: - -``` no_run -#![feature(link_args)] - -#[link_args = "-foo -bar -baz"] -extern {} -# fn main() {} -``` - -Note that this feature is currently hidden behind the `feature(link_args)` gate -because this is not a sanctioned way of performing linking. Right now rustc -shells out to the system linker, so it makes sense to provide extra command line -arguments, but this will not always be the case. In the future rustc may use -LLVM directly to link native libraries in which case `link_args` will have no -meaning. - -It is highly recommended to *not* use this attribute, and rather use the more -formal `#[link(...)]` attribute on `extern` blocks instead. - diff --git a/src/doc/trpl/loops.md b/src/doc/trpl/loops.md new file mode 100644 index 0000000000..a91fb8dada --- /dev/null +++ b/src/doc/trpl/loops.md @@ -0,0 +1,209 @@ +% Loops + +Rust currently provides three approaches to performing some kind of iterative activity. They are: `loop`, `while` and `for`. Each approach has its own set of uses. + +## loop + +The infinite `loop` is the simplest form of loop available in Rust. Using the keyword `loop`, Rust provides a way to loop indefinitely until some terminating statement is reached. Rust's infinite `loop`s look like this: + +```rust,ignore +loop { + println!("Loop forever!"); +} +``` + +## while + +Rust also has a `while` loop. It looks like this: + +```rust +let mut x = 5; // mut x: i32 +let mut done = false; // mut done: bool + +while !done { + x += x - 3; + + println!("{}", x); + + if x % 5 == 0 { + done = true; + } +} +``` + +`while` loops are the correct choice when you’re not sure how many times +you need to loop. + +If you need an infinite loop, you may be tempted to write this: + +```rust,ignore +while true { +``` + +However, `loop` is far better suited to handle this case: + +```rust,ignore +loop { +``` + +Rust’s control-flow analysis treats this construct differently than a `while +true`, since we know that it will always loop. In general, the more information +we can give to the compiler, the better it can do with safety and code +generation, so you should always prefer `loop` when you plan to loop +infinitely. + +## for + +The `for` loop is used to loop a particular number of times. Rust’s `for` loops +work a bit differently than in other systems languages, however. Rust’s `for` +loop doesn’t look like this “C-style” `for` loop: + +```c +for (x = 0; x < 10; x++) { + printf( "%d\n", x ); +} +``` + +Instead, it looks like this: + +```rust +for x in 0..10 { + println!("{}", x); // x: i32 +} +``` + +In slightly more abstract terms, + +```ignore +for var in expression { + code +} +``` + +The expression is an [iterator][iterator]. The iterator gives back a series of +elements. Each element is one iteration of the loop. That value is then bound +to the name `var`, which is valid for the loop body. Once the body is over, the +next value is fetched from the iterator, and we loop another time. When there +are no more values, the `for` loop is over. + +[iterator]: iterators.html + +In our example, `0..10` is an expression that takes a start and an end position, +and gives an iterator over those values. The upper bound is exclusive, though, +so our loop will print `0` through `9`, not `10`. + +Rust does not have the “C-style” `for` loop on purpose. Manually controlling +each element of the loop is complicated and error prone, even for experienced C +developers. + +### Enumerate + +When you need to keep track of how many times you already looped, you can use the `.enumerate()` function. + +#### On ranges: + +```rust +for (i,j) in (5..10).enumerate() { + println!("i = {} and j = {}", i, j); +} +``` + +Outputs: + +```text +i = 0 and j = 5 +i = 1 and j = 6 +i = 2 and j = 7 +i = 3 and j = 8 +i = 4 and j = 9 +``` + +Don't forget to add the parentheses around the range. + +#### On iterators: + +```rust +# let lines = "hello\nworld".lines(); +for (linenumber, line) in lines.enumerate() { + println!("{}: {}", linenumber, line); +} +``` + +Outputs: + +```text +0: Content of line one +1: Content of line two +2: Content of line tree +3: Content of line four +``` + +## Ending iteration early + +Let’s take a look at that `while` loop we had earlier: + +```rust +let mut x = 5; +let mut done = false; + +while !done { + x += x - 3; + + println!("{}", x); + + if x % 5 == 0 { + done = true; + } +} +``` + +We had to keep a dedicated `mut` boolean variable binding, `done`, to know +when we should exit out of the loop. Rust has two keywords to help us with +modifying iteration: `break` and `continue`. + +In this case, we can write the loop in a better way with `break`: + +```rust +let mut x = 5; + +loop { + x += x - 3; + + println!("{}", x); + + if x % 5 == 0 { break; } +} +``` + +We now loop forever with `loop` and use `break` to break out early. Issuing an explicit `return` statement will also serve to terminate the loop early. + +`continue` is similar, but instead of ending the loop, goes to the next +iteration. This will only print the odd numbers: + +```rust +for x in 0..10 { + if x % 2 == 0 { continue; } + + println!("{}", x); +} +``` + +## Loop labels + +You may also encounter situations where you have nested loops and need to +specify which one your `break` or `continue` statement is for. Like most +other languages, by default a `break` or `continue` will apply to innermost +loop. In a sitation where you would like to a `break` or `continue` for one +of the outer loops, you can use labels to specify which loop the `break` or + `continue` statement applies to. This will only print when both `x` and `y` are + odd: + +```rust +'outer: for x in 0..10 { + 'inner: for y in 0..10 { + if x % 2 == 0 { continue 'outer; } // continues the loop over x + if y % 2 == 0 { continue 'inner; } // continues the loop over y + println!("x: {}, y: {}", x, y); + } +} +``` diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md index 0a985334b5..e530a9f105 100644 --- a/src/doc/trpl/no-stdlib.md +++ b/src/doc/trpl/no-stdlib.md @@ -39,6 +39,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} # // fn main() {} tricked you, rustdoc! ``` @@ -63,6 +64,7 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 { #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} # // fn main() {} tricked you, rustdoc! ``` @@ -150,6 +152,7 @@ extern fn panic_fmt(args: &core::fmt::Arguments, #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} # #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 } # fn main() {} ``` diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 46af311acf..5ddbdd6df0 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -42,8 +42,8 @@ With that in mind, let’s learn about ownership. # Ownership [Variable bindings][bindings] have a property in Rust: they ‘have ownership’ -of what they’re bound to. This means that when a binding goes out of scope, the -resource that they’re bound to are freed. For example: +of what they’re bound to. This means that when a binding goes out of scope, +Rust will free the bound resources. For example: ```rust fn foo() { diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 7a1f8bf21b..1abd4ca6c2 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -112,26 +112,55 @@ match x { } ``` -# Ignoring variants +# Ignoring bindings -If you’re matching on an enum which has variants, you can use `..` to -ignore the value and type in the variant: +You can use `_` in a pattern to disregard the type and value. +For example, here’s a `match` against a `Result`: ```rust -enum OptionalInt { - Value(i32), +# let some_value: Result = Err("There was an error"); +match some_value { + Ok(value) => println!("got a value: {}", value), + Err(_) => println!("an error occurred"), +} +``` + +In the first arm, we bind the value inside the `Ok` variant to `value`. But +in the `Err` arm, we use `_` to disregard the specific error, and just print +a general error message. + +`_` is valid in any pattern that creates a binding. This can be useful to +ignore parts of a larger structure: + +```rust +fn coordinate() -> (i32, i32, i32) { + // generate and return some sort of triple tuple +# (1, 2, 3) +} + +let (x, _, z) = coordinate(); +``` + +Here, we bind the first and last element of the tuple to `x` and `z`, but +ignore the middle element. + +Similarly, you can use `..` in a pattern to disregard multiple values. + +```rust +enum OptionalTuple { + Value(i32, i32, i32), Missing, } -let x = OptionalInt::Value(5); +let x = OptionalTuple::Value(5, -2, 3); match x { - OptionalInt::Value(..) => println!("Got an int!"), - OptionalInt::Missing => println!("No such luck."), + OptionalTuple::Value(..) => println!("Got a tuple!"), + OptionalTuple::Missing => println!("No such luck."), } ``` -This prints `Got an int!`. +This prints `Got a tuple!`. # Guards diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index b27db2ab7b..d1d3063138 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -336,7 +336,9 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as the borrow ‘doesn’t live long enough’ because it’s not valid for the right amount of time. -The same problem occurs when the reference is declared _before_ the variable it refers to: +The same problem occurs when the reference is declared _before_ the variable it +refers to. This is because resources within the same scope are freed in the +opposite order they were declared: ```rust,ignore let y: &i32; @@ -369,3 +371,6 @@ statement 1 at 3:14 println!("{}", y); } ``` + +In the above example, `y` is declared before `x`, meaning that `y` lives longer +than `x`, which is not allowed. diff --git a/src/doc/trpl/release-channels.md b/src/doc/trpl/release-channels.md index 03e65539a2..1e203c6553 100644 --- a/src/doc/trpl/release-channels.md +++ b/src/doc/trpl/release-channels.md @@ -43,3 +43,26 @@ This will help alert the team in case there’s an accidental regression. Additionally, testing against nightly can catch regressions even sooner, and so if you don’t mind a third build, we’d appreciate testing against all channels. +As an example, many Rust programmers use [Travis](https://travis-ci.org/) to +test their crates, which is free for open source projects. Travis [supports +Rust directly][travis], and you can use a `.travis.yml` file like this to +test on all channels: + +```yaml +language: rust +rust: + - nightly + - beta + - stable + +matrix: + allow_failures: + - rust: nightly +``` + +[travis]: http://docs.travis-ci.com/user/languages/rust/ + +With this configuration, Travis will test all three channels, but if something +breaks on nightly, it won’t fail your build. A similar configuration is +recommended for any CI system, check the documentation of the one you’re +using for more details. diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index 759543140b..a5a0127031 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -250,11 +250,10 @@ that our tests are entirely left out of a normal build. The second change is the `use` declaration. Because we're in an inner module, we need to bring our test function into scope. This can be annoying if you have -a large module, and so this is a common use of the `glob` feature. Let's change -our `src/lib.rs` to make use of it: +a large module, and so this is a common use of globs. Let's change our +`src/lib.rs` to make use of it: ```rust,ignore - pub fn add_two(a: i32) -> i32 { a + 2 } diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index 2c5f5927fd..cfab268a7c 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -73,7 +73,7 @@ frame. But before we can show what happens when `foo()` is called, we need to visualize what’s going on with memory. Your operating system presents a view of memory to your program that’s pretty simple: a huge list of addresses, from 0 to a large number, representing how much RAM your computer has. For example, if -you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,824`. That +you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That number comes from 230, the number of bytes in a gigabyte. This memory is kind of like a giant array: addresses start at zero and go @@ -176,7 +176,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and | 1 | a | 5 | | 0 | x | 42 | -And then `foo()` ends, leaving just `main()` +And then `foo()` ends, leaving just `main()`: | Address | Name | Value | |---------|------|-------| @@ -537,7 +537,7 @@ Generally, you should prefer stack allocation, and so, Rust stack-allocates by default. The LIFO model of the stack is simpler, at a fundamental level. This has two big impacts: runtime efficiency and semantic impact. -## Runtime Efficiency. +## Runtime Efficiency Managing the memory for the stack is trivial: The machine just increments or decrements a single value, the so-called “stack pointer”. @@ -551,7 +551,7 @@ is a great introduction. [wilson]: http://www.cs.northwestern.edu/~pdinda/icsclass/doc/dsa.pdf -## Semantic impact +## Semantic impact Stack-allocation impacts the Rust language itself, and thus the developer’s mental model. The LIFO semantics is what drives how the Rust language handles diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 687e2bbf00..740e2d51c4 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -347,40 +347,50 @@ easiest just to show an example: ```rust trait Foo { - fn bar(&self); + fn is_valid(&self) -> bool; - fn baz(&self) { println!("We called baz."); } + fn is_invalid(&self) -> bool { !self.is_valid() } } ``` -Implementors of the `Foo` trait need to implement `bar()`, but they don’t -need to implement `baz()`. They’ll get this default behavior. They can +Implementors of the `Foo` trait need to implement `is_valid()`, but they don’t +need to implement `is_invalid()`. They’ll get this default behavior. They can override the default if they so choose: ```rust # trait Foo { -# fn bar(&self); -# fn baz(&self) { println!("We called baz."); } +# fn is_valid(&self) -> bool; +# +# fn is_invalid(&self) -> bool { !self.is_valid() } # } struct UseDefault; impl Foo for UseDefault { - fn bar(&self) { println!("We called bar."); } + fn is_valid(&self) -> bool { + println!("Called UseDefault.is_valid."); + true + } } struct OverrideDefault; impl Foo for OverrideDefault { - fn bar(&self) { println!("We called bar."); } + fn is_valid(&self) -> bool { + println!("Called OverrideDefault.is_valid."); + true + } - fn baz(&self) { println!("Override baz!"); } + fn is_invalid(&self) -> bool { + println!("Called OverrideDefault.is_invalid!"); + true // this implementation is a self-contradiction! + } } let default = UseDefault; -default.baz(); // prints "We called baz." +assert!(!default.is_invalid()); // prints "Called UseDefault.is_valid." let over = OverrideDefault; -over.baz(); // prints "Override baz!" +assert!(over.is_invalid()); // prints "Called OverrideDefault.is_invalid!" ``` # Inheritance diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index fdb9c33a2b..1b223365bd 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -8,11 +8,11 @@ this, Rust has a keyword, `unsafe`. Code using `unsafe` has less restrictions than normal code does. Let’s go over the syntax, and then we’ll talk semantics. `unsafe` is used in -two contexts. The first one is to mark a function as unsafe: +four contexts. The first one is to mark a function as unsafe: ```rust unsafe fn danger_will_robinson() { - // scary stuff + // scary stuff } ``` @@ -27,15 +27,40 @@ unsafe { } ``` +The third is for unsafe traits: + +```rust +unsafe trait Scary { } +``` + +And the fourth is for `impl`ementing one of those traits: + +```rust +# unsafe trait Scary { } +unsafe impl Scary for i32 {} +``` + It’s important to be able to explicitly delineate code that may have bugs that cause big problems. If a Rust program segfaults, you can be sure it’s somewhere in the sections marked `unsafe`. # What does ‘safe’ mean? -Safe, in the context of Rust, means “doesn’t do anything unsafe.” Easy! +Safe, in the context of Rust, means ‘doesn’t do anything unsafe’. It’s also +important to know that there are certain behaviors that are probably not +desirable in your code, but are expressly _not_ unsafe: -Okay, let’s try again: what is not safe to do? Here’s a list: +* Deadlocks +* Leaks of memory or other resources +* Exiting without calling destructors +* Integer overflow + +Rust cannot prevent all kinds of software problems. Buggy code can and will be +written in Rust. These things aren’t great, but they don’t qualify as `unsafe` +specifically. + +In addition, the following are all undefined behaviors in Rust, and must be +avoided, even when writing `unsafe` code: * Data races * Dereferencing a null/dangling raw pointer @@ -64,21 +89,6 @@ Okay, let’s try again: what is not safe to do? Here’s a list: [undef]: http://llvm.org/docs/LangRef.html#undefined-values [aliasing]: http://llvm.org/docs/LangRef.html#pointer-aliasing-rules -Whew! That’s a bunch of stuff. It’s also important to notice all kinds of -behaviors that are certainly bad, but are expressly _not_ unsafe: - -* Deadlocks -* Reading data from private fields -* Leaks due to reference count cycles -* Exiting without calling destructors -* Sending signals -* Accessing/modifying the file system -* Integer overflow - -Rust cannot prevent all kinds of software problems. Buggy code can and will be -written in Rust. These things aren’t great, but they don’t qualify as `unsafe` -specifically. - # Unsafe Superpowers In both unsafe functions and unsafe blocks, Rust will let you do three things @@ -90,10 +100,14 @@ that you normally can not do. Just three. Here they are: That’s it. It’s important that `unsafe` does not, for example, ‘turn off the borrow checker’. Adding `unsafe` to some random Rust code doesn’t change its -semantics, it won’t just start accepting anything. +semantics, it won’t just start accepting anything. But it will let you write +things that _do_ break some of the rules. + +You will also encounter the `unsafe` keyword when writing bindings to foreign +(non-Rust) interfaces. You're encouraged to write a safe, native Rust interface +around the methods provided by the library. -But it will let you write things that _do_ break some of the rules. Let’s go -over these three abilities in order. +Let’s go over the basic three abilities listed, in order. ## Access or update a `static mut` diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md deleted file mode 100644 index 0f5c3c64a4..0000000000 --- a/src/doc/trpl/while-loops.md +++ /dev/null @@ -1,93 +0,0 @@ -% while Loops - -Rust also has a `while` loop. It looks like this: - -```rust -let mut x = 5; // mut x: i32 -let mut done = false; // mut done: bool - -while !done { - x += x - 3; - - println!("{}", x); - - if x % 5 == 0 { - done = true; - } -} -``` - -`while` loops are the correct choice when you’re not sure how many times -you need to loop. - -If you need an infinite loop, you may be tempted to write this: - -```rust,ignore -while true { -``` - -However, Rust has a dedicated keyword, `loop`, to handle this case: - -```rust,ignore -loop { -``` - -Rust’s control-flow analysis treats this construct differently than a `while -true`, since we know that it will always loop. In general, the more information -we can give to the compiler, the better it can do with safety and code -generation, so you should always prefer `loop` when you plan to loop -infinitely. - -## Ending iteration early - -Let’s take a look at that `while` loop we had earlier: - -```rust -let mut x = 5; -let mut done = false; - -while !done { - x += x - 3; - - println!("{}", x); - - if x % 5 == 0 { - done = true; - } -} -``` - -We had to keep a dedicated `mut` boolean variable binding, `done`, to know -when we should exit out of the loop. Rust has two keywords to help us with -modifying iteration: `break` and `continue`. - -In this case, we can write the loop in a better way with `break`: - -```rust -let mut x = 5; - -loop { - x += x - 3; - - println!("{}", x); - - if x % 5 == 0 { break; } -} -``` - -We now loop forever with `loop` and use `break` to break out early. - -`continue` is similar, but instead of ending the loop, goes to the next -iteration. This will only print the odd numbers: - -```rust -for x in 0..10 { - if x % 2 == 0 { continue; } - - println!("{}", x); -} -``` - -Both `continue` and `break` are valid in both `while` loops and [`for` loops][for]. - -[for]: for-loops.html diff --git a/src/etc/ctags.rust b/src/etc/ctags.rust index 59a2ae205c..4397f290a5 100644 --- a/src/etc/ctags.rust +++ b/src/etc/ctags.rust @@ -5,7 +5,7 @@ --regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/ --regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/ --regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/ ---regex-Rust=/^[ \t]*(pub[ \t]+)?static[ \t]+([a-zA-Z0-9_]+)/\2/c,consts,static constants/ ---regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/ ---regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]*<[^>]*>)?[ \t]+(([a-zA-Z0-9_:]+)[ \t]*(<[^>]*>)?[ \t]+(for)[ \t]+)?([a-zA-Z0-9_]+)/\4 \6 \7/i,impls,trait implementations/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?(static|const)[ \t]+(mut[ \t]+)?([a-zA-Z0-9_]+)/\4/c,consts,static constants/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?(unsafe[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\3/t,traits,traits/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?(unsafe[ \t]+)?impl([ \t\n]*<[^>]*>)?[ \t]+(([a-zA-Z0-9_:]+)[ \t]*(<[^>]*>)?[ \t]+(for)[ \t]+)?([a-zA-Z0-9_]+)/\5 \7 \8/i,impls,trait implementations/ --regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/ diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index 6e667b37a9..06a83c7593 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -55,12 +55,10 @@ SLICE_FIELD_NAME_LENGTH = "length" SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH] # std::Vec<> related constants -STD_VEC_FIELD_NAME_DATA_PTR = "ptr" STD_VEC_FIELD_NAME_LENGTH = "len" -STD_VEC_FIELD_NAME_CAPACITY = "cap" -STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_DATA_PTR, - STD_VEC_FIELD_NAME_LENGTH, - STD_VEC_FIELD_NAME_CAPACITY] +STD_VEC_FIELD_NAME_BUF = "buf" +STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF, + STD_VEC_FIELD_NAME_LENGTH] # std::String related constants STD_STRING_FIELD_NAMES = ["vec"] @@ -302,13 +300,13 @@ def get_discriminant_value_as_integer(enum_val): def extract_length_ptr_and_cap_from_std_vec(vec_val): assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH) - ptr_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_DATA_PTR) - cap_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_CAPACITY) + buf_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_BUF) length = vec_val.get_child_at_index(length_field_index).as_integer() - vec_ptr_val = vec_val.get_child_at_index(ptr_field_index) - capacity = vec_val.get_child_at_index(cap_field_index).as_integer() + buf = vec_val.get_child_at_index(buf_field_index) + vec_ptr_val = buf.get_child_at_index(0) + capacity = buf.get_child_at_index(1).as_integer() unique_ptr_val = vec_ptr_val.get_child_at_index(0) data_ptr = unique_ptr_val.get_child_at_index(0) assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR diff --git a/src/etc/errorck.py b/src/etc/errorck.py index 4b1b78da9f..48736542f2 100644 --- a/src/etc/errorck.py +++ b/src/etc/errorck.py @@ -23,6 +23,18 @@ src_dir = sys.argv[1] errcode_map = {} error_re = re.compile("(E\d\d\d\d)") +# In the register_long_diagnostics! macro, entries look like this: +# +# EXXXX: r##" +# +# "##, +# +# These two variables are for detecting the beginning and end of diagnostic +# messages so that duplicate error codes are not reported when a code occurs +# inside a diagnostic message +long_diag_begin = "r##\"" +long_diag_end = "\"##" + for (dirpath, dirnames, filenames) in os.walk(src_dir): if "src/test" in dirpath or "src/llvm" in dirpath: # Short circuit for fast @@ -35,7 +47,14 @@ for (dirpath, dirnames, filenames) in os.walk(src_dir): path = os.path.join(dirpath, filename) with open(path, 'r') as f: + inside_long_diag = False for line_num, line in enumerate(f, start=1): + if inside_long_diag: + # Skip duplicate error code checking for this line + if long_diag_end in line: + inside_long_diag = False + continue + match = error_re.search(line) if match: errcode = match.group(1) @@ -47,6 +66,9 @@ for (dirpath, dirnames, filenames) in os.walk(src_dir): else: errcode_map[errcode] = new_record + if long_diag_begin in line: + inside_long_diag = True + errors = False all_errors = [] diff --git a/src/etc/mklldeps.py b/src/etc/mklldeps.py index 7a925fa3f3..1cc65406b2 100644 --- a/src/etc/mklldeps.py +++ b/src/etc/mklldeps.py @@ -14,10 +14,9 @@ import subprocess f = open(sys.argv[1], 'wb') -components = sys.argv[2].split(' ') -components = [i for i in components if i] # ignore extra whitespaces +components = sys.argv[2].split() # splits on whitespace enable_static = sys.argv[3] -llconfig = sys.argv[4] +llvm_config = sys.argv[4] f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -39,7 +38,7 @@ def run(args): out, err = proc.communicate() if err: - print("failed to run llconfig: args = `{}`".format(args)) + print("failed to run llvm_config: args = `{}`".format(args)) print(err) sys.exit(1) return out @@ -47,7 +46,7 @@ def run(args): f.write("\n") # LLVM libs -args = [llconfig, '--libs', '--system-libs'] +args = [llvm_config, '--libs', '--system-libs'] args.extend(components) out = run(args) @@ -69,13 +68,13 @@ for lib in out.strip().replace("\n", ' ').split(' '): f.write(")]\n") # LLVM ldflags -out = run([llconfig, '--ldflags']) +out = run([llvm_config, '--ldflags']) for lib in out.strip().split(' '): if lib[:2] == "-l": f.write("#[link(name = \"" + lib[2:] + "\")]\n") # C++ runtime library -out = run([llconfig, '--cxxflags']) +out = run([llvm_config, '--cxxflags']) if enable_static == '1': assert('stdlib=libc++' not in out) f.write("#[link(name = \"stdc++\", kind = \"static\")]\n") diff --git a/src/etc/snapshot.py b/src/etc/snapshot.py index 0349ccf9b6..6d62a45c70 100644 --- a/src/etc/snapshot.py +++ b/src/etc/snapshot.py @@ -41,13 +41,14 @@ download_dir_base = "dl" download_unpack_base = os.path.join(download_dir_base, "unpack") snapshot_files = { + "bitrig": ["bin/rustc"], + "dragonfly": ["bin/rustc"], + "freebsd": ["bin/rustc"], "linux": ["bin/rustc"], "macos": ["bin/rustc"], - "winnt": ["bin/rustc.exe"], - "freebsd": ["bin/rustc"], - "dragonfly": ["bin/rustc"], - "bitrig": ["bin/rustc"], + "netbsd": ["bin/rustc"], "openbsd": ["bin/rustc"], + "winnt": ["bin/rustc.exe"], } winnt_runtime_deps_32 = ["libgcc_s_dw2-1.dll", "libstdc++-6.dll"] @@ -103,6 +104,8 @@ def get_kernel(triple): return "dragonfly" if os_name == "bitrig": return "bitrig" + if os_name == "netbsd": + return "netbsd" if os_name == "openbsd": return "openbsd" return "linux" diff --git a/src/etc/snapshot.pyc b/src/etc/snapshot.pyc deleted file mode 100644 index befb4641396a47922821ff21446a086a582c6236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10137 zcmc&)O>Z38b-mS1HrW&@iljt}GqR>NBWhaGG%0B&j6lpdmPN@@U~q(@64@Ma+Qq8s z?xKoSt$NiW=^+s$;{f?ij37W32Ase~5FiK;{{+Kc1_-jq)>-5i1X*O4-Saf`O^J2ir=r{Yt9!$0{l4=i){7tj%+!-`hsi~ zdikPk6?^#+*&6BPM`dfYmoLdysh1y=nzhRhF|3q>1gHlGSc*61gd@ zJKe9F?&r?*b2I(itgLQf+jA0}l_ti0Ljufg^KVKpulu5?s*C+Y)?5Gw(=nQ8Sk%cuO-&5>zyEMS@G3c~^qBHB*(~9nD;o;Id|} zNwB1u>k?ei%zF~NtC<=Bv01GGA<_Th--hoX%P-&}ckwl=NOF-~$f+pLMkQO8ydX!y z6Ub3hU=519z(|3Wn<#AJgg2`rcyuEwascAcGkz3RIk?tUS%(oY$Dzq5@%tjoOq3?| zC~2fQAI=Zkp+35En1?1Wp(+UdGzfK+oI~w!?V^eKHgYSibT3@VIws%gL~*cUGG9wI zE$*cGiiy1!;fl$d&e%9H!fN2cZ zBF-ges*s;T?(Y3>)HmI`_4S9Yc@yQm$e1W;R>I^(<%O43hT83xGv7?1UvC1loFC+- zhMHEMx6RrL7nn!>GS^m%y`;IEW=&Q$!yC2!Q#c8TBv#3ElD6kRGiB85M2T+N*G22b zG`HvZsnL1+J(j}*E8_hqN%DLQPdBnK+%ZAUk%G)?rb#0{)G2nNJd2vzDQ$-dI+ed2&wiY-Z)E2w7$7seA9il7%C`V-#?#8;E4_c42SL;s5>!rpTJ~oFEe4CbKgeETtp(pS!bkRza?kFIpZv#RB{$I z?{nGw_Q5=Z0yq}P0cL^2Mp5QBt30d?Ln2ZA?yB{Ysp;Qx?q$n6-@Rq`%HiAvCg+)) zMRH<7IETp~ggo-%dhdAZiMJPij0Od>I7P?jZuupn-(?FIIlSwmqBKSZ8-EMUU$k*- z|K+`N&{y`Z^w~146O#dHtI>&H5x`^A4g^4T$NRRBLg24}vjVgO$p!&q7}0|OO$ zR#R>2A_yx{&OrkUKnZw@hV=otWs~KSmcK>z((<^LTl8Y}q%xPlb}1W|rdtuM z+HKl#l6NP z>dLrR(WWwVulIU+nSXL1=fP7te!G(*YsQg?Gp7Pk0Z<5iQX>&VyE>4wNFfZ-I?py)pxlSib|aGR(1pi(W121y(~a# z&?56V870dr zX;TlcmZ%(VszY0=(F^kOkCv8}j0*O_y*ulwe(r}DOuduTwzR$6Iw!knl&Ck0TS6TZ z*=q%X+lazAI57c}YU9+0k%cp**Pq`(P4|v*!6`dFiu$k5LA0$H#KsD&dH6T{$Nq`Z}<9Z6zA3c zm=EKO$+Mzl|0IVqyp`?ZN~SRf=SeanBT!|AnEr+#CPtHRa{<9%XnR}Z17$v7Z;y;Z zZC1M3(n zh8AE3VoUg@?d>Ny-KPfpt2%Doen&$P?ysTFPU*$5dxs@jjZOllf2Qp8@#Z~V#a!M$ zv@HwigKK<6DX^nyLr1|b8aWq%t5_#XG+Kg^)%hgD5-$#|9zaVh2 zN^rF<@(X9H=*&1%aJi-jCb)=RiZ0%^ESdl?pa!M`#uvwCu9L_CH&ib44;Br)-Ye?5 zQ6~+;EMI%|Cf&PTTsD_5MJHhlNRJO^QsKq95+xNboAO<&s8g(Bb{ElKFQ9q~?gbRB zS*BX>YIL%VtE2CIA(auBO@#R~fYu|lRa zCu*|M1o1jR6ootRayZO}l2*23og2;s=Bqb4iEn}1CVMCr`%X?4dVzIvs2Q#BAc&d> z=vfJJc?a%8qyzH%l7XtLpul+6|G*tkX^0eC#sjYd7cBTvxL!ry#^6}zhcrs7p%Fi|CKROt5@ zW?Tdn-!+Kym^|F8WSu0B_QFaK!Y2*F#E;;m(q-0=VC~@cYJK$sJ@H9N0VayU0_9deK<8_0rE3!!fR>t@bUDY#Zdhhfa7nK}>xd(ZO}oP43H?#HJkKR-ByBRnx8$J3H8%I+KNb7Y^! zPdCCG;l#!7F@6z+O=93fB(GakoW4Z`4wkQWZg)K}5I*X0wr^pXL+^47De;r1Pgk~W z%;Rw}VhtqL#16{p~U(57_W+TC@SfV*Gbs`N#NgY8|jX3=?ie0*& zh1Tev_SX<@RsPUW>`g-j`V{XqR;oy@{syk}%hv|&H#8KyLHbKO;6E}%Wk1SW6_N+| z_E~6s2c^-WNau=q9|PalhcFYK;-hA*GEo6xPCSZ3&xDmd56^oQAEl(CFQk?Yg^5lY zmDAM?kIJ_>M%lI%WkHQzz@d6TuXf4@?Nz>}ay2T$HMzgZRi9(^@T=g?DihA2UUSX+&nQHGXP6y^ds>DxAS9 ztqIhR13S|NwJGEn0$-7G6;_5w843hj?}8_&7$ItKnMaDFMGD6OO*RAom*Gch^7L}C zzWrC~Gyrcz5QYS5;0vgyKtEzaOfJtKDuPBN`w44cpn5p6W#9<7pvnG)wi8Y8W5$Tx zN6&x3=X;MKRDf=_JdSRd4g;2v!y@s(2s`8N2|#ZCn{0(wDFgHs#mqabJf#7Jv6tTq z12DABa5;cd><=#ks&uGdLn(s@mYe7d|B9eBB=2ERla6{8Da|UqXg4g&dleivU2+Bn zT;=;eX6|L2yMMwu!rNu=#}YRgS3P;{c^ zgotD9L0{`H!F~dmH4HBh@{{U7zYhF)ywxS}$MkmsZ-=M=>^E1aQs~y`slCH^;(o^D zkjd{d(d#v1A^i~0vW9=$k5Q-QgqL+V7Rn;HJl}LbWec_I;a(fDM2+{TSwgG+CgHxl zK$ARhIl#@xT}Rd)($|@zQd+*Ew&NXM5~p6E!5G@v{H0nL+q%~BEC+q{|Bz^d%TT}D zWYS=wuy}_#BEmWjd{tu6ME}wTnIAAWa3;1`e98m_AZq#DKVt6tO#Twd02Z42l5hUw znDN8CH0Z?PS1E6^gM`*|=u;@7#9I~8V!3n<2R~gnkF?~RLmOGK_n9i [char; 3] { - match bsearch_case_table(c, to_titlecase_table) { - None => [c, '\\0', '\\0'], - Some(index) => to_titlecase_table[index].1 - } - } - fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option { match table.binary_search_by(|&(key, _)| { if c == key { Equal } @@ -400,9 +393,6 @@ def emit_conversions_module(f, to_upper, to_lower, to_title): emit_table(f, "to_uppercase_table", sorted(to_upper.iteritems(), key=operator.itemgetter(0)), is_pub=False, t_type = t_type, pfun=pfun) - emit_table(f, "to_titlecase_table", - sorted(to_title.iteritems(), key=operator.itemgetter(0)), - is_pub=False, t_type = t_type, pfun=pfun) f.write("}\n\n") def emit_grapheme_module(f, grapheme_table, grapheme_cats): diff --git a/src/jemalloc/VERSION b/src/jemalloc/VERSION index 4f4246ff1d..1babfed182 100644 --- a/src/jemalloc/VERSION +++ b/src/jemalloc/VERSION @@ -1 +1 @@ -0.12.0-10860-g082e4763615bdbe7b4dd3dfd6fc2210b7773edf5 +0.12.0-12255-g9a92aaf19a64603b02b4130fe52958cc12488900 diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index dd9c1d1fd1..46b6a5722e 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -78,14 +78,18 @@ use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::fmt; use core::cmp::Ordering; use core::mem::{align_of_val, size_of_val}; -use core::intrinsics::drop_in_place; +use core::intrinsics::{drop_in_place, abort}; use core::mem; use core::nonzero::NonZero; use core::ops::{Deref, CoerceUnsized}; +use core::ptr; use core::marker::Unsize; use core::hash::{Hash, Hasher}; +use core::{usize, isize}; use heap::deallocate; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + /// An atomically reference counted wrapper for shared state. /// /// # Examples @@ -145,6 +149,8 @@ pub struct Weak { unsafe impl Send for Weak { } unsafe impl Sync for Weak { } +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -154,7 +160,12 @@ impl fmt::Debug for Weak { struct ArcInner { strong: atomic::AtomicUsize, + + // the value usize::MAX acts as a sentinel for temporarily "locking" the + // ability to upgrade weak pointers or downgrade strong ones; this is used + // to avoid races in `make_unique` and `get_mut`. weak: atomic::AtomicUsize, + data: T, } @@ -191,7 +202,8 @@ impl Arc { /// # Examples /// /// ``` - /// # #![feature(arc_weak)] + /// #![feature(arc_weak)] + /// /// use std::sync::Arc; /// /// let five = Arc::new(5); @@ -201,9 +213,25 @@ impl Arc { #[unstable(feature = "arc_weak", reason = "Weak pointers may not belong in this module.")] pub fn downgrade(&self) -> Weak { - // See the clone() impl for why this is relaxed - self.inner().weak.fetch_add(1, Relaxed); - Weak { _ptr: self._ptr } + loop { + // This Relaxed is OK because we're checking the value in the CAS + // below. + let cur = self.inner().weak.load(Relaxed); + + // check if the weak counter is currently "locked"; if so, spin. + if cur == usize::MAX { continue } + + // NOTE: this code currently ignores the possibility of overflow + // into usize::MAX; in general both Rc and Arc need to be adjusted + // to deal with overflow. + + // Unlike with Clone(), we need this to be an Acquire read to + // synchronize with the write coming from `is_unique`, so that the + // events prior to that write happen before this read. + if self.inner().weak.compare_and_swap(cur, cur + 1, Acquire) == cur { + return Weak { _ptr: self._ptr } + } + } } /// Get the number of weak references to this value. @@ -258,51 +286,6 @@ pub fn weak_count(this: &Arc) -> usize { Arc::weak_count(this) } #[deprecated(since = "1.2.0", reason = "renamed to Arc::strong_count")] pub fn strong_count(this: &Arc) -> usize { Arc::strong_count(this) } - -/// Returns a mutable reference to the contained value if the `Arc` is unique. -/// -/// Returns `None` if the `Arc` is not unique. -/// -/// This function is marked **unsafe** because it is racy if weak pointers -/// are active. -/// -/// # Examples -/// -/// ``` -/// # #![feature(arc_unique, alloc)] -/// extern crate alloc; -/// # fn main() { -/// use alloc::arc::{Arc, get_mut}; -/// -/// # unsafe { -/// let mut x = Arc::new(3); -/// *get_mut(&mut x).unwrap() = 4; -/// assert_eq!(*x, 4); -/// -/// let _y = x.clone(); -/// assert!(get_mut(&mut x).is_none()); -/// # } -/// # } -/// ``` -#[inline] -#[unstable(feature = "arc_unique")] -#[deprecated(since = "1.2.0", - reason = "this function is unsafe with weak pointers")] -pub unsafe fn get_mut(this: &mut Arc) -> Option<&mut T> { - // FIXME(#24880) potential race with upgraded weak pointers here - if Arc::strong_count(this) == 1 && Arc::weak_count(this) == 0 { - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. - let inner = &mut **this._ptr; - Some(&mut inner.data) - } else { - None - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { /// Makes a clone of the `Arc`. @@ -331,7 +314,21 @@ impl Clone for Arc { // another must already provide any required synchronization. // // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - self.inner().strong.fetch_add(1, Relaxed); + let old_size = self.inner().strong.fetch_add(1, Relaxed); + + // However we need to guard against massive refcounts in case someone + // is `mem::forget`ing Arcs. If we don't do this the count can overflow + // and users will use-after free. We racily saturate to `isize::MAX` on + // the assumption that there aren't ~2 billion threads incrementing + // the reference count at once. This branch will never be taken in + // any realistic program. + // + // We abort because such a program is incredibly degenerate, and we + // don't care to support it. + if old_size > MAX_REFCOUNT { + unsafe { abort(); } + } + Arc { _ptr: self._ptr } } } @@ -350,44 +347,152 @@ impl Arc { /// Make a mutable reference from the given `Arc`. /// /// This is also referred to as a copy-on-write operation because the inner - /// data is cloned if the reference count is greater than one. - /// - /// This method is marked **unsafe** because it is racy if weak pointers - /// are active. + /// data is cloned if the (strong) reference count is greater than one. If + /// we hold the only strong reference, any existing weak references will no + /// longer be upgradeable. /// /// # Examples /// /// ``` - /// # #![feature(arc_unique)] + /// #![feature(arc_unique)] + /// /// use std::sync::Arc; /// - /// # unsafe { /// let mut five = Arc::new(5); /// - /// let mut_five = five.make_unique(); - /// # } + /// let mut_five = Arc::make_unique(&mut five); /// ``` #[inline] #[unstable(feature = "arc_unique")] - #[deprecated(since = "1.2.0", - reason = "this function is unsafe with weak pointers")] - pub unsafe fn make_unique(&mut self) -> &mut T { - // FIXME(#24880) potential race with upgraded weak pointers here + pub fn make_unique(this: &mut Arc) -> &mut T { + // Note that we hold both a strong reference and a weak reference. + // Thus, releasing our strong reference only will not, by itself, cause + // the memory to be deallocated. // - // Note that we hold a strong reference, which also counts as a weak - // reference, so we only clone if there is an additional reference of - // either kind. - if self.inner().strong.load(SeqCst) != 1 || - self.inner().weak.load(SeqCst) != 1 { - *self = Arc::new((**self).clone()) + // Use Acquire to ensure that we see any writes to `weak` that happen + // before release writes (i.e., decrements) to `strong`. Since we hold a + // weak count, there's no chance the ArcInner itself could be + // deallocated. + if this.inner().strong.compare_and_swap(1, 0, Acquire) != 1 { + // Another srong pointer exists; clone + *this = Arc::new((**this).clone()); + } else if this.inner().weak.load(Relaxed) != 1 { + // Relaxed suffices in the above because this is fundamentally an + // optimization: we are always racing with weak pointers being + // dropped. Worst case, we end up allocated a new Arc unnecessarily. + + // We removed the last strong ref, but there are additional weak + // refs remaining. We'll move the contents to a new Arc, and + // invalidate the other weak refs. + + // Note that it is not possible for the read of `weak` to yield + // usize::MAX (i.e., locked), since the weak count can only be + // locked by a thread with a strong reference. + + // Materialize our own implicit weak pointer, so that it can clean + // up the ArcInner as needed. + let weak = Weak { _ptr: this._ptr }; + + // mark the data itself as already deallocated + unsafe { + // there is no data race in the implicit write caused by `read` + // here (due to zeroing) because data is no longer accessed by + // other threads (due to there being no more strong refs at this + // point). + let mut swap = Arc::new(ptr::read(&(**weak._ptr).data)); + mem::swap(this, &mut swap); + mem::forget(swap); + } + } else { + // We were the sole reference of either kind; bump back up the + // strong ref count. + this.inner().strong.store(1, Release); } + // As with `get_mut()`, the unsafety is ok because our reference was // either unique to begin with, or became one upon cloning the contents. - let inner = &mut **self._ptr; - &mut inner.data + unsafe { + let inner = &mut **this._ptr; + &mut inner.data + } } } +impl Arc { + /// Returns a mutable reference to the contained value if the `Arc` is unique. + /// + /// Returns `None` if the `Arc` is not unique. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_unique, alloc)] + /// + /// extern crate alloc; + /// # fn main() { + /// use alloc::arc::Arc; + /// + /// let mut x = Arc::new(3); + /// *Arc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = x.clone(); + /// assert!(Arc::get_mut(&mut x).is_none()); + /// # } + /// ``` + #[inline] + #[unstable(feature = "arc_unique")] + pub fn get_mut(this: &mut Arc) -> Option<&mut T> { + if this.is_unique() { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + unsafe { + let inner = &mut **this._ptr; + Some(&mut inner.data) + } + } else { + None + } + } + + /// Determine whether this is the unique reference (including weak refs) to + /// the underlying data. + /// + /// Note that this requires locking the weak ref count. + fn is_unique(&mut self) -> bool { + // lock the weak pointer count if we appear to be the sole weak pointer + // holder. + // + // The acquire label here ensures a happens-before relationship with any + // writes to `strong` prior to decrements of the `weak` count (via drop, + // which uses Release). + if self.inner().weak.compare_and_swap(1, usize::MAX, Acquire) == 1 { + // Due to the previous acquire read, this will observe any writes to + // `strong` that were due to upgrading weak pointers; only strong + // clones remain, which require that the strong count is > 1 anyway. + let unique = self.inner().strong.load(Relaxed) == 1; + + // The release write here synchronizes with a read in `downgrade`, + // effectively preventing the above read of `strong` from happening + // after the write. + self.inner().weak.store(1, Release); // release the lock + unique + } else { + false + } + } +} + +#[inline] +#[unstable(feature = "arc_unique")] +#[deprecated(since = "1.2", reason = "use Arc::get_mut instead")] +pub fn get_mut(this: &mut Arc) -> Option<&mut T> { + Arc::get_mut(this) +} + #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Arc { /// Drops the `Arc`. @@ -469,7 +574,8 @@ impl Weak { /// # Examples /// /// ``` - /// # #![feature(arc_weak)] + /// #![feature(arc_weak)] + /// /// use std::sync::Arc; /// /// let five = Arc::new(5); @@ -483,9 +589,15 @@ impl Weak { // fetch_add because once the count hits 0 it must never be above 0. let inner = self.inner(); loop { - let n = inner.strong.load(SeqCst); + // Relaxed load because any write of 0 that we can observe + // leaves the field in a permanently zero state (so a + // "stale" read of 0 is fine), and any other value is + // confirmed via the CAS below. + let n = inner.strong.load(Relaxed); if n == 0 { return None } - let old = inner.strong.compare_and_swap(n, n + 1, SeqCst); + + // Relaxed is valid for the same reason it is on Arc's Clone impl + let old = inner.strong.compare_and_swap(n, n + 1, Relaxed); if old == n { return Some(Arc { _ptr: self._ptr }) } } } @@ -507,7 +619,8 @@ impl Clone for Weak { /// # Examples /// /// ``` - /// # #![feature(arc_weak)] + /// #![feature(arc_weak)] + /// /// use std::sync::Arc; /// /// let weak_five = Arc::new(5).downgrade(); @@ -516,9 +629,18 @@ impl Clone for Weak { /// ``` #[inline] fn clone(&self) -> Weak { - // See comments in Arc::clone() for why this is relaxed - self.inner().weak.fetch_add(1, Relaxed); - Weak { _ptr: self._ptr } + // See comments in Arc::clone() for why this is relaxed. This can use a + // fetch_add (ignoring the lock) because the weak count is only locked + // where are *no other* weak pointers in existence. (So we can't be + // running this code in that case). + let old_size = self.inner().weak.fetch_add(1, Relaxed); + + // See comments in Arc::clone() for why we do this (for mem::forget). + if old_size > MAX_REFCOUNT { + unsafe { abort(); } + } + + return Weak { _ptr: self._ptr } } } @@ -531,7 +653,8 @@ impl Drop for Weak { /// # Examples /// /// ``` - /// # #![feature(arc_weak)] + /// #![feature(arc_weak)] + /// /// use std::sync::Arc; /// /// { @@ -561,6 +684,11 @@ impl Drop for Weak { // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about // the memory orderings + // + // It's not necessary to check for the locked state here, because the + // weak count can only be locked if there was precisely one weak ref, + // meaning that drop could only subsequently run ON that remaining weak + // ref, which can only happen after the lock is released. if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { deallocate(ptr as *mut u8, @@ -792,13 +920,13 @@ mod tests { let mut cow1 = cow0.clone(); let mut cow2 = cow1.clone(); - assert!(75 == *cow0.make_unique()); - assert!(75 == *cow1.make_unique()); - assert!(75 == *cow2.make_unique()); + assert!(75 == *Arc::make_unique(&mut cow0)); + assert!(75 == *Arc::make_unique(&mut cow1)); + assert!(75 == *Arc::make_unique(&mut cow2)); - *cow0.make_unique() += 1; - *cow1.make_unique() += 2; - *cow2.make_unique() += 3; + *Arc::make_unique(&mut cow0) += 1; + *Arc::make_unique(&mut cow1) += 2; + *Arc::make_unique(&mut cow2) += 3; assert!(76 == *cow0); assert!(77 == *cow1); @@ -822,7 +950,7 @@ mod tests { assert!(75 == *cow2); unsafe { - *cow0.make_unique() += 1; + *Arc::make_unique(&mut cow0) += 1; } assert!(76 == *cow0); @@ -845,7 +973,7 @@ mod tests { assert!(75 == *cow1_weak.upgrade().unwrap()); unsafe { - *cow0.make_unique() += 1; + *Arc::make_unique(&mut cow0) += 1; } assert!(76 == *cow0); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1039756363..9420a88bad 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -55,14 +55,18 @@ use core::prelude::*; +use heap; +use raw_vec::RawVec; + use core::any::Any; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; -use core::marker::Unsize; +use core::marker::{self, Unsize}; use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; -use core::ptr::{Unique}; +use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; +use core::ptr::{self, Unique}; use core::raw::{TraitObject}; /// A value that represents the heap. This is the default place that the `box` @@ -71,8 +75,9 @@ use core::raw::{TraitObject}; /// The following two examples are equivalent: /// /// ``` -/// # #![feature(box_heap)] -/// #![feature(box_syntax)] +/// #![feature(box_heap)] +/// +/// #![feature(box_syntax, placement_in_syntax)] /// use std::boxed::HEAP; /// /// fn main() { @@ -83,7 +88,15 @@ use core::raw::{TraitObject}; #[lang = "exchange_heap"] #[unstable(feature = "box_heap", reason = "may be renamed; uncertain about custom allocator design")] -pub const HEAP: () = (); +#[allow(deprecated)] +pub const HEAP: ExchangeHeapSingleton = + ExchangeHeapSingleton { _force_singleton: () }; + +/// This the singleton type used solely for `boxed::HEAP`. +#[unstable(feature = "box_heap", + reason = "may be renamed; uncertain about custom allocator design")] +#[derive(Copy, Clone)] +pub struct ExchangeHeapSingleton { _force_singleton: () } /// A pointer type for heap allocation. /// @@ -91,7 +104,97 @@ pub const HEAP: () = (); #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] #[fundamental] -pub struct Box(Unique); +pub struct Box(Unique); + +/// `IntermediateBox` represents uninitialized backing storage for `Box`. +/// +/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of +/// introducing a separate `IntermediateBox`; but then you hit +/// issues when you e.g. attempt to destructure an instance of `Box`, +/// since it is a lang item and so it gets special handling by the +/// compiler. Easier just to make this parallel type for now. +/// +/// FIXME (pnkfelix): Currently the `box` protocol only supports +/// creating instances of sized types. This IntermediateBox is +/// designed to be forward-compatible with a future protocol that +/// supports creating instances of unsized types; that is why the type +/// parameter has the `?Sized` generalization marker, and is also why +/// this carries an explicit size. However, it probably does not need +/// to carry the explicit alignment; that is just a work-around for +/// the fact that the `align_of` intrinsic currently requires the +/// input type to be Sized (which I do not think is strictly +/// necessary). +#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")] +pub struct IntermediateBox{ + ptr: *mut u8, + size: usize, + align: usize, + marker: marker::PhantomData<*mut T>, +} + +impl Place for IntermediateBox { + fn pointer(&mut self) -> *mut T { + unsafe { ::core::mem::transmute(self.ptr) } + } +} + +unsafe fn finalize(b: IntermediateBox) -> Box { + let p = b.ptr as *mut T; + mem::forget(b); + mem::transmute(p) +} + +fn make_place() -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + let p = if size == 0 { + heap::EMPTY as *mut u8 + } else { + let p = unsafe { + heap::allocate(size, align) + }; + if p.is_null() { + panic!("Box make_place allocation failure."); + } + p + }; + + IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData } +} + +impl BoxPlace for IntermediateBox { + fn make_place() -> IntermediateBox { make_place() } +} + +impl InPlace for IntermediateBox { + type Owner = Box; + unsafe fn finalize(self) -> Box { finalize(self) } +} + +impl Boxed for Box { + type Data = T; + type Place = IntermediateBox; + unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } +} + +impl Placer for ExchangeHeapSingleton { + type Place = IntermediateBox; + + fn make_place(self) -> IntermediateBox { + make_place() + } +} + +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr, self.size, self.align) + } + } + } +} impl Box { /// Allocates memory on the heap and then moves `x` into it. @@ -116,7 +219,7 @@ impl Box { /// of `T` and releases memory. Since the way `Box` allocates and /// releases memory is unspecified, the only valid pointer to pass /// to this function is the one taken from another `Box` with - /// `boxed::into_raw` function. + /// `Box::into_raw` function. /// /// Function is unsafe, because improper use of this function may /// lead to memory problems like double-free, for example if the @@ -139,11 +242,10 @@ impl Box { /// /// # Examples /// ``` - /// # #![feature(box_raw)] - /// use std::boxed; + /// #![feature(box_raw)] /// /// let seventeen = Box::new(17u32); - /// let raw = boxed::into_raw(seventeen); + /// let raw = Box::into_raw(seventeen); /// let boxed_again = unsafe { Box::from_raw(raw) }; /// ``` #[unstable(feature = "box_raw", reason = "may be renamed")] @@ -164,7 +266,8 @@ impl Box { /// /// # Examples /// ``` -/// # #![feature(box_raw)] +/// #![feature(box_raw)] +/// /// use std::boxed; /// /// let seventeen = Box::new(17u32); @@ -202,13 +305,13 @@ impl Clone for Box { /// ``` #[inline] fn clone(&self) -> Box { box {(**self).clone()} } - /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples /// /// ``` - /// # #![feature(box_raw)] + /// #![feature(box_raw)] + /// /// let x = Box::new(5); /// let mut y = Box::new(10); /// @@ -222,6 +325,19 @@ impl Clone for Box { } } + +#[stable(feature = "box_slice_clone", since = "1.3.0")] +impl Clone for Box { + fn clone(&self) -> Self { + let len = self.len(); + let buf = RawVec::with_capacity(len); + unsafe { + ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); + mem::transmute(buf.into_box()) // bytes to str ~magic + } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for Box { #[inline] @@ -416,3 +532,55 @@ impl<'a,A,R> FnOnce for Box+Send+'a> { } impl, U: ?Sized> CoerceUnsized> for Box {} + +#[stable(feature = "box_slice_clone", since = "1.3.0")] +impl Clone for Box<[T]> { + fn clone(&self) -> Self { + let mut new = BoxBuilder { + data: RawVec::with_capacity(self.len()), + len: 0 + }; + + let mut target = new.data.ptr(); + + for item in self.iter() { + unsafe { + ptr::write(target, item.clone()); + target = target.offset(1); + }; + + new.len += 1; + } + + return unsafe { new.into_box() }; + + // Helper type for responding to panics correctly. + struct BoxBuilder { + data: RawVec, + len: usize, + } + + impl BoxBuilder { + unsafe fn into_box(self) -> Box<[T]> { + let raw = ptr::read(&self.data); + mem::forget(self); + raw.into_box() + } + } + + impl Drop for BoxBuilder { + fn drop(&mut self) { + let mut data = self.data.ptr(); + let max = unsafe { data.offset(self.len as isize) }; + + while data != max { + unsafe { + ptr::read(data); + data = data.offset(1); + } + } + } + } + } +} + diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index fc44ac4eac..2ef23b26a5 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -76,9 +76,9 @@ fn deref() { #[test] fn raw_sized() { + let x = Box::new(17); + let p = Box::into_raw(x); unsafe { - let x = Box::new(17); - let p = boxed::into_raw(x); assert_eq!(17, *p); *p = 19; let y = Box::from_raw(p); @@ -105,9 +105,9 @@ fn raw_trait() { } } + let x: Box = Box::new(Bar(17)); + let p = Box::into_raw(x); unsafe { - let x: Box = Box::new(Bar(17)); - let p = boxed::into_raw(x); assert_eq!(17, (*p).get()); (*p).set(19); let y: Box = Box::from_raw(p); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7dcf7a76da..0e9b01e5c2 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -76,18 +76,23 @@ #![feature(core)] #![feature(core_intrinsics)] #![feature(core_prelude)] +#![feature(core_slice_ext)] #![feature(custom_attribute)] #![feature(fundamental)] #![feature(lang_items)] #![feature(no_std)] #![feature(nonzero)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] +#![feature(placement_new_protocol)] #![feature(raw)] #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(unique)] #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(unsize)] +#![feature(core_slice_ext)] +#![feature(core_str_ext)] #![cfg_attr(test, feature(test, alloc, rustc_private, box_raw))] #![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")), @@ -122,6 +127,7 @@ mod boxed { pub use std::boxed::{Box, HEAP}; } mod boxed_test; pub mod arc; pub mod rc; +pub mod raw_vec; /// Common out-of-memory routine #[cold] @@ -133,19 +139,3 @@ pub fn oom() -> ! { // allocate. unsafe { core::intrinsics::abort() } } - -// FIXME(#14344): When linking liballoc with libstd, this library will be linked -// as an rlib (it only exists as an rlib). It turns out that an -// optimized standard library doesn't actually use *any* symbols -// from this library. Everything is inlined and optimized away. -// This means that linkers will actually omit the object for this -// file, even though it may be needed in the future. -// -// To get around this for now, we define a dummy symbol which -// will never get inlined so the stdlib can call it. The stdlib's -// reference to this symbol will cause this library's object file -// to get linked in to libstd successfully (the linker won't -// optimize it out). -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -pub fn fixme_14344_be_sure_to_link_to_collections() {} diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs new file mode 100644 index 0000000000..9311f44d9d --- /dev/null +++ b/src/liballoc/raw_vec.rs @@ -0,0 +1,453 @@ +// Copyright 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::ptr::Unique; +use core::mem; +use core::slice::{self, SliceExt}; +use heap; +use super::oom; +use super::boxed::Box; +use core::ops::Drop; + +/// A low-level utility for more ergonomically allocating, reallocating, and deallocating a +/// a buffer of memory on the heap without having to worry about all the corner cases +/// involved. This type is excellent for building your own data structures like Vec and VecDeque. +/// In particular: +/// +/// * Produces heap::EMPTY on zero-sized types +/// * Produces heap::EMPTY on zero-length allocations +/// * Catches all overflows in capacity computations (promotes them to "capacity overflow" panics) +/// * Guards against 32-bit systems allocating more than isize::MAX bytes +/// * Guards against overflowing your length +/// * Aborts on OOM +/// * Avoids freeing heap::EMPTY +/// * Contains a ptr::Unique and thus endows the user with all related benefits +/// +/// This type does not in anyway inspect the memory that it manages. When dropped it *will* +/// free its memory, but it *won't* try to Drop its contents. It is up to the user of RawVec +/// to handle the actual things *stored* inside of a RawVec. +/// +/// Note that a RawVec always forces its capacity to be usize::MAX for zero-sized types. +/// This enables you to use capacity growing logic catch the overflows in your length +/// that might occur with zero-sized types. +/// +/// However this means that you need to be careful when roundtripping this type +/// with a `Box<[T]>`: `cap()` won't yield the len. However `with_capacity`, +/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity +/// field. This allows zero-sized types to not be special-cased by consumers of +/// this type. +#[unsafe_no_drop_flag] +pub struct RawVec { + ptr: Unique, + cap: usize, +} + +impl RawVec { + /// Creates the biggest possible RawVec without allocating. If T has positive + /// size, then this makes a RawVec with capacity 0. If T has 0 size, then it + /// it makes a RawVec with capacity `usize::MAX`. Useful for implementing + /// delayed allocation. + pub fn new() -> Self { + unsafe { + // !0 is usize::MAX. This branch should be stripped at compile time. + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + + // heap::EMPTY doubles as "unallocated" and "zero-sized allocation" + RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap } + } + } + + /// Creates a RawVec with exactly the capacity and alignment requirements + /// for a `[T; cap]`. This is equivalent to calling RawVec::new when `cap` is 0 + /// or T is zero-sized. Note that if `T` is zero-sized this means you will *not* + /// get a RawVec with the requested capacity! + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + pub fn with_capacity(cap: usize) -> Self { + unsafe { + let elem_size = mem::size_of::(); + + let alloc_size = cap.checked_mul(elem_size).expect("capacity overflow"); + alloc_guard(alloc_size); + + // handles ZSTs and `cap = 0` alike + let ptr = if alloc_size == 0 { + heap::EMPTY as *mut u8 + } else { + let align = mem::align_of::(); + let ptr = heap::allocate(alloc_size, align); + if ptr.is_null() { oom() } + ptr + }; + + RawVec { ptr: Unique::new(ptr as *mut _), cap: cap } + } + } + + /// Reconstitutes a RawVec from a pointer and capacity. + /// + /// # Undefined Behaviour + /// + /// The ptr must be allocated, and with the given capacity. The + /// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems). + /// If the ptr and capacity come from a RawVec, then this is guaranteed. + pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self { + RawVec { ptr: Unique::new(ptr), cap: cap } + } + + /// Converts a `Box<[T]>` into a `RawVec`. + pub fn from_box(mut slice: Box<[T]>) -> Self { + unsafe { + let result = RawVec::from_raw_parts(slice.as_mut_ptr(), slice.len()); + mem::forget(slice); + result + } + } +} + +impl RawVec { + /// Gets a raw pointer to the start of the allocation. Note that this is + /// heap::EMPTY if `cap = 0` or T is zero-sized. In the former case, you must + /// be careful. + pub fn ptr(&self) -> *mut T { + *self.ptr + } + + /// Gets the capacity of the allocation. + /// + /// This will always be `usize::MAX` if `T` is zero-sized. + pub fn cap(&self) -> usize { + if mem::size_of::() == 0 { !0 } else { self.cap } + } + + /// Doubles the size of the type's backing allocation. This is common enough + /// to want to do that it's easiest to just have a dedicated method. Slightly + /// more efficient logic can be provided for this than the general case. + /// + /// This function is ideal for when pushing elements one-at-a-time because + /// you don't need to incur the costs of the more general computations + /// reserve needs to do to guard against overflow. You do however need to + /// manually check if your `len == cap`. + /// + /// # Panics + /// + /// * Panics if T is zero-sized on the assumption that you managed to exhaust + /// all `usize::MAX` slots in your imaginary buffer. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + /// + /// # Examples + /// + /// ```ignore + /// struct MyVec { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// pub fn push(&mut self, elem: T) { + /// if self.len == self.buf.cap() { self.buf.double(); } + /// // double would have aborted or panicked if the len exceeded + /// // `isize::MAX` so this is safe to do unchecked now. + /// unsafe { + /// ptr::write(self.buf.ptr().offset(self.len as isize), elem); + /// } + /// self.len += 1; + /// } + /// } + /// ``` + #[inline(never)] + #[cold] + pub fn double(&mut self) { + unsafe { + let elem_size = mem::size_of::(); + + // since we set the capacity to usize::MAX when elem_size is + // 0, getting to here necessarily means the RawVec is overfull. + assert!(elem_size != 0, "capacity overflow"); + + let align = mem::align_of::(); + + let (new_cap, ptr) = if self.cap == 0 { + // skip to 4 because tiny Vec's are dumb; but not if that would cause overflow + let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; + let ptr = heap::allocate(new_cap * elem_size, align); + (new_cap, ptr) + } else { + // Since we guarantee that we never allocate more than isize::MAX bytes, + // `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow + let new_cap = 2 * self.cap; + let new_alloc_size = new_cap * elem_size; + alloc_guard(new_alloc_size); + let ptr = heap::reallocate(self.ptr() as *mut _, + self.cap * elem_size, + new_alloc_size, + align); + (new_cap, ptr) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } + + /// Ensures that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already, + /// will reallocate the minimum possible amount of memory necessary. + /// Generally this will be exactly the amount of memory necessary, + /// but in principle the allocator is free to give back more than + /// we asked for. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behaviour of this function may break. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { + unsafe { + let elem_size = mem::size_of::(); + let align = mem::align_of::(); + + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. + // Wrapping in case they gave a bad `used_cap`. + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; } + + // Nothing we can really do about these checks :( + let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow"); + let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow"); + alloc_guard(new_alloc_size); + + let ptr = if self.cap == 0 { + heap::allocate(new_alloc_size, align) + } else { + heap::reallocate(self.ptr() as *mut _, + self.cap * elem_size, + new_alloc_size, + align) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } + + /// Ensures that the buffer contains at least enough space to hold + /// `used_cap + needed_extra_cap` elements. If it doesn't already have + /// enough capacity, will reallocate enough space plus comfortable slack + /// space to get amortized `O(1)` behaviour. Will limit this behaviour + /// if it would needlessly cause itself to panic. + /// + /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate + /// the requested space. This is not really unsafe, but the unsafe + /// code *you* write that relies on the behaviour of this function may break. + /// + /// This is ideal for implementing a bulk-push operation like `extend`. + /// + /// # Panics + /// + /// * Panics if the requested capacity exceeds `usize::MAX` bytes. + /// * Panics on 32-bit platforms if the requested capacity exceeds + /// `isize::MAX` bytes. + /// + /// # Aborts + /// + /// Aborts on OOM + /// + /// # Examples + /// + /// ```ignore + /// struct MyVec { + /// buf: RawVec, + /// len: usize, + /// } + /// + /// impl MyVec { + /// pub fn push_all(&mut self, elems: &[T]) { + /// self.buf.reserve(self.len, elems.len()); + /// // reserve would have aborted or panicked if the len exceeded + /// // `isize::MAX` so this is safe to do unchecked now. + /// for x in elems { + /// unsafe { + /// ptr::write(self.buf.ptr().offset(self.len as isize), x.clone()); + /// } + /// self.len += 1; + /// } + /// } + /// } + /// ``` + pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { + unsafe { + let elem_size = mem::size_of::(); + let align = mem::align_of::(); + + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. + // Wrapping in case they give a bas `used_cap` + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; } + + // Nothing we can really do about these checks :( + let new_cap = used_cap.checked_add(needed_extra_cap) + .and_then(|cap| cap.checked_mul(2)) + .expect("capacity overflow"); + let new_alloc_size = new_cap.checked_mul(elem_size).expect("capacity overflow"); + // FIXME: may crash and burn on over-reserve + alloc_guard(new_alloc_size); + + let ptr = if self.cap == 0 { + heap::allocate(new_alloc_size, align) + } else { + heap::reallocate(self.ptr() as *mut _, + self.cap * elem_size, + new_alloc_size, + align) + }; + + // If allocate or reallocate fail, we'll get `null` back + if ptr.is_null() { oom() } + + self.ptr = Unique::new(ptr as *mut _); + self.cap = new_cap; + } + } + + /// Shrinks the allocation down to the specified amount. If the given amount + /// is 0, actually completely deallocates. + /// + /// # Panics + /// + /// Panics if the given amount is *larger* than the current capacity. + /// + /// # Aborts + /// + /// Aborts on OOM. + pub fn shrink_to_fit(&mut self, amount: usize) { + let elem_size = mem::size_of::(); + let align = mem::align_of::(); + + // Set the `cap` because they might be about to promote to a `Box<[T]>` + if elem_size == 0 { + self.cap = amount; + return; + } + + // This check is my waterloo; it's the only thing Vec wouldn't have to do. + assert!(self.cap >= amount, "Tried to shrink to a larger capacity"); + + if amount == 0 { + mem::replace(self, RawVec::new()); + } else if self.cap != amount { + unsafe { + // Overflow check is unnecessary as the vector is already at + // least this large. + let ptr = heap::reallocate(self.ptr() as *mut _, + self.cap * elem_size, + amount * elem_size, + align); + if ptr.is_null() { oom() } + self.ptr = Unique::new(ptr as *mut _); + } + self.cap = amount; + } + } + + /// Converts the entire buffer into `Box<[T]>`. + /// + /// While it is not *strictly* Undefined Behaviour to call + /// this procedure while some of the RawVec is unintialized, + /// it cetainly makes it trivial to trigger it. + /// + /// Note that this will correctly reconstitute any `cap` changes + /// that may have been performed. (see description of type for details) + pub unsafe fn into_box(self) -> Box<[T]> { + // NOTE: not calling `cap()` here, actually using the real `cap` field! + let slice = slice::from_raw_parts_mut(self.ptr(), self.cap); + let output: Box<[T]> = Box::from_raw(slice); + mem::forget(self); + output + } + + /// This is a stupid name in the hopes that someone will find this in the + /// not too distant future and remove it with the rest of + /// #[unsafe_no_drop_flag] + pub fn unsafe_no_drop_flag_needs_drop(&self) -> bool { + self.cap != mem::POST_DROP_USIZE + } +} + +impl Drop for RawVec { + /// Frees the memory owned by the RawVec *without* trying to Drop its contents. + fn drop(&mut self) { + let elem_size = mem::size_of::(); + if elem_size != 0 && self.cap != 0 && self.unsafe_no_drop_flag_needs_drop() { + let align = mem::align_of::(); + + let num_bytes = elem_size * self.cap; + unsafe { + heap::deallocate(*self.ptr as *mut _, num_bytes, align); + } + } + } +} + + + +// We need to guarantee the following: +// * We don't ever allocate `> isize::MAX` byte-size objects +// * We don't overflow `usize::MAX` and actually allocate too little +// +// On 64-bit we just need to check for overflow since trying to allocate +// `> isize::MAX` bytes will surely fail. On 32-bit we need to add an extra +// guard for this in case we're running on a platform which can use all 4GB in +// user-space. e.g. PAE or x32 + +#[inline] +#[cfg(target_pointer_width = "64")] +fn alloc_guard(_alloc_size: usize) { } + +#[inline] +#[cfg(target_pointer_width = "32")] +fn alloc_guard(alloc_size: usize) { + assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow"); +} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3dfafd0a37..e4e3b3b209 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -91,7 +91,8 @@ //! documentation for more details on interior mutability. //! //! ```rust -//! # #![feature(rc_weak)] +//! #![feature(rc_weak)] +//! //! use std::rc::Rc; //! use std::rc::Weak; //! use std::cell::RefCell; @@ -160,7 +161,7 @@ use core::cell::Cell; use core::cmp::Ordering; use core::fmt; use core::hash::{Hasher, Hash}; -use core::intrinsics::{assume, drop_in_place}; +use core::intrinsics::{assume, drop_in_place, abort}; use core::marker::{self, Unsize}; use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget}; use core::nonzero::NonZero; @@ -227,7 +228,8 @@ impl Rc { /// # Examples /// /// ``` - /// # #![feature(rc_unique)] + /// #![feature(rc_unique)] + /// /// use std::rc::Rc; /// /// let x = Rc::new(3); @@ -262,7 +264,8 @@ impl Rc { /// # Examples /// /// ``` - /// # #![feature(rc_weak)] + /// #![feature(rc_weak)] + /// /// use std::rc::Rc; /// /// let five = Rc::new(5); @@ -292,7 +295,8 @@ impl Rc { /// # Examples /// /// ``` - /// # #![feature(rc_unique)] + /// #![feature(rc_unique)] + /// /// use std::rc::Rc; /// /// let five = Rc::new(5); @@ -313,7 +317,8 @@ impl Rc { /// # Examples /// /// ``` - /// # #![feature(rc_unique)] + /// #![feature(rc_unique)] + /// /// use std::rc::Rc; /// /// let mut x = Rc::new(3); @@ -353,7 +358,8 @@ pub fn strong_count(this: &Rc) -> usize { Rc::strong_count(this) } /// # Examples /// /// ``` -/// # #![feature(rc_unique)] +/// #![feature(rc_unique)] +/// /// use std::rc; /// use std::rc::Rc; /// @@ -373,7 +379,8 @@ pub fn is_unique(rc: &Rc) -> bool { Rc::is_unique(rc) } /// # Examples /// /// ``` -/// # #![feature(rc_unique)] +/// #![feature(rc_unique)] +/// /// use std::rc::{self, Rc}; /// /// let x = Rc::new(3); @@ -395,7 +402,8 @@ pub fn try_unwrap(rc: Rc) -> Result> { Rc::try_unwrap(rc) } /// # Examples /// /// ``` -/// # #![feature(rc_unique)] +/// #![feature(rc_unique)] +/// /// use std::rc::{self, Rc}; /// /// let mut x = Rc::new(3); @@ -419,7 +427,8 @@ impl Rc { /// # Examples /// /// ``` - /// # #![feature(rc_unique)] + /// #![feature(rc_unique)] + /// /// use std::rc::Rc; /// /// let mut five = Rc::new(5); @@ -734,6 +743,8 @@ pub struct Weak { impl !marker::Send for Weak {} impl !marker::Sync for Weak {} +impl, U: ?Sized> CoerceUnsized> for Weak {} + #[unstable(feature = "rc_weak", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -748,7 +759,8 @@ impl Weak { /// # Examples /// /// ``` - /// # #![feature(rc_weak)] + /// #![feature(rc_weak)] + /// /// use std::rc::Rc; /// /// let five = Rc::new(5); @@ -776,7 +788,8 @@ impl Drop for Weak { /// # Examples /// /// ``` - /// # #![feature(rc_weak)] + /// #![feature(rc_weak)] + /// /// use std::rc::Rc; /// /// { @@ -823,7 +836,8 @@ impl Clone for Weak { /// # Examples /// /// ``` - /// # #![feature(rc_weak)] + /// #![feature(rc_weak)] + /// /// use std::rc::Rc; /// /// let weak_five = Rc::new(5).downgrade(); @@ -844,6 +858,15 @@ impl fmt::Debug for Weak { } } +// NOTE: We checked_add here to deal with mem::forget safety. In particular +// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then +// you can free the allocation while outstanding Rcs (or Weaks) exist. +// We abort because this is such a degenerate scenario that we don't care about +// what happens -- no real program should ever experience this. +// +// This should have negligible overhead since you don't actually need to +// clone these much in Rust thanks to ownership and move-semantics. + #[doc(hidden)] trait RcBoxPtr { fn inner(&self) -> &RcBox; @@ -852,7 +875,9 @@ trait RcBoxPtr { fn strong(&self) -> usize { self.inner().strong.get() } #[inline] - fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + fn inc_strong(&self) { + self.inner().strong.set(self.strong().checked_add(1).unwrap_or_else(|| unsafe { abort() })); + } #[inline] fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } @@ -861,7 +886,9 @@ trait RcBoxPtr { fn weak(&self) -> usize { self.inner().weak.get() } #[inline] - fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } + fn inc_weak(&self) { + self.inner().weak.set(self.weak().checked_add(1).unwrap_or_else(|| unsafe { abort() })); + } #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index f6204173ed..ddf6191894 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -216,7 +216,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let heap = BinaryHeap::from_vec(vec![9, 1, 2, 7, 3, 2]); /// ``` @@ -236,7 +237,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); /// @@ -341,7 +343,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::from_vec(vec![1, 3]); /// @@ -387,7 +390,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); /// heap.push(1); @@ -419,7 +423,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let mut heap = BinaryHeap::new(); /// @@ -445,7 +450,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4, 5, 6, 7]); /// let vec = heap.into_vec(); @@ -463,7 +469,8 @@ impl BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// /// let mut heap = BinaryHeap::from_vec(vec![1, 2, 4, 5, 7]); @@ -724,7 +731,8 @@ impl IntoIterator for BinaryHeap { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::BinaryHeap; /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); /// diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 51914900fd..30f23e073f 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![deprecated(reason = "BitVec and BitSet have been migrated to cargo as bit-vec and bit-set", + since = "1.3.0")] +#![unstable(feature = "collections", reason = "deprecated")] +#![allow(deprecated)] + // FIXME(Gankro): BitVec and BitSet are very tightly coupled. Ideally (for // maintenance), they should be in separate files/modules, with BitSet only // using BitVec's public API. This will be hard for performance though, because @@ -38,7 +43,8 @@ //! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes //! //! ``` -//! # #![feature(bitset, bitvec, range_inclusive, step_by)] +//! #![feature(bitset, bitvec, range_inclusive, step_by)] +//! //! use std::collections::{BitSet, BitVec}; //! use std::iter; //! @@ -134,7 +140,8 @@ const FALSE: &'static bool = &false; /// # Examples /// /// ``` -/// # #![feature(bitvec)] +/// #![feature(bitvec)] +/// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(10, false); @@ -251,7 +258,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// let mut bv = BitVec::new(); /// ``` @@ -266,7 +274,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_elem(10, false); @@ -278,7 +287,7 @@ impl BitVec { pub fn from_elem(nbits: usize, bit: bool) -> BitVec { let nblocks = blocks_for_bits(nbits); let mut bit_vec = BitVec { - storage: repeat(if bit { !0 } else { 0 }).take(nblocks).collect(), + storage: vec![if bit { !0 } else { 0 }; nblocks], nbits: nbits }; bit_vec.fix_last_block(); @@ -307,7 +316,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_bytes(&[0b10100000, 0b00010010]); @@ -350,7 +360,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_fn(5, |i| { i % 2 == 0 }); @@ -369,7 +380,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_bytes(&[0b01100000]); @@ -402,7 +414,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(5, false); @@ -425,7 +438,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let before = 0b01100000; @@ -446,7 +460,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let before = 0b01100000; @@ -475,7 +490,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let a = 0b01100100; @@ -506,7 +522,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let a = 0b01100100; @@ -537,7 +554,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let a = 0b01100100; @@ -567,7 +585,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(5, true); @@ -592,7 +611,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]); @@ -609,7 +629,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec, append)] + /// #![feature(bitvec, append)] + /// /// use std::collections::BitVec; /// /// let mut a = BitVec::from_bytes(&[0b10000000]); @@ -652,7 +673,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec, split_off)] + /// #![feature(bitvec, split_off)] + /// /// use std::collections::BitVec; /// let mut a = BitVec::new(); /// a.push(true); @@ -713,7 +735,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(10, false); @@ -731,7 +754,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(10, false); @@ -753,7 +777,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(3, true); @@ -801,7 +826,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let bv = BitVec::from_bytes(&[0b10100000]); @@ -822,7 +848,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_bytes(&[0b01001011]); @@ -849,7 +876,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(3, false); @@ -880,7 +908,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_elem(3, false); @@ -903,7 +932,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::new(); @@ -925,7 +955,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_bytes(&[0b01001011]); @@ -976,7 +1007,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::from_bytes(&[0b01001001]); @@ -1007,7 +1039,8 @@ impl BitVec { /// # Examples /// /// ``` - /// # #![feature(bitvec)] + /// #![feature(bitvec)] + /// /// use std::collections::BitVec; /// /// let mut bv = BitVec::new(); @@ -1226,7 +1259,8 @@ impl<'a> IntoIterator for &'a BitVec { /// # Examples /// /// ``` -/// # #![feature(bitvec, bitset)] +/// #![feature(bitvec, bitset)] +/// /// use std::collections::{BitSet, BitVec}; /// /// // It's a regular set @@ -1330,7 +1364,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1347,7 +1382,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::with_capacity(100); @@ -1365,7 +1401,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitVec, BitSet}; /// /// let bv = BitVec::from_bytes(&[0b01100000]); @@ -1387,7 +1424,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::with_capacity(100); @@ -1409,7 +1447,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1436,7 +1475,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1457,7 +1497,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1478,7 +1519,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1525,7 +1567,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset)] + /// #![feature(bitset)] + /// /// use std::collections::BitSet; /// /// let mut s = BitSet::new(); @@ -1558,7 +1601,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitVec, BitSet}; /// /// let s = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01001010])); @@ -1580,7 +1624,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitVec, BitSet}; /// /// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000])); @@ -1610,7 +1655,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitVec, BitSet}; /// /// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000])); @@ -1641,7 +1687,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000])); @@ -1679,7 +1726,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000])); @@ -1707,7 +1755,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = 0b01101000; @@ -1731,7 +1780,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = 0b01101000; @@ -1756,7 +1806,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = 0b01101000; @@ -1789,7 +1840,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec)] + /// #![feature(bitset, bitvec)] + /// /// use std::collections::{BitSet, BitVec}; /// /// let a = 0b01101000; @@ -1813,7 +1865,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec, append)] + /// #![feature(bitset, bitvec, append)] + /// /// use std::collections::{BitVec, BitSet}; /// /// let mut a = BitSet::new(); @@ -1844,7 +1897,8 @@ impl BitSet { /// # Examples /// /// ``` - /// # #![feature(bitset, bitvec, split_off)] + /// #![feature(bitset, bitvec, split_off)] + /// /// use std::collections::{BitSet, BitVec}; /// let mut a = BitSet::new(); /// a.insert(2); diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index d7242b9077..1c75636cb0 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -215,7 +215,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned { impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { /// Acquires a mutable reference to the owned form of the data. /// - /// Copies the data if it is not already owned. + /// Clones the data if it is not already owned. /// /// # Examples /// @@ -241,7 +241,7 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { /// Extracts the owned data. /// - /// Copies the data if it is not already owned. + /// Clones the data if it is not already owned. /// /// # Examples /// diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 27b10213ec..a5a0d86457 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1504,7 +1504,8 @@ impl BTreeMap { /// # Examples /// /// ``` - /// # #![feature(btree_range, collections_bound)] + /// #![feature(btree_range, collections_bound)] + /// /// use std::collections::BTreeMap; /// use std::collections::Bound::{Included, Unbounded}; /// @@ -1531,7 +1532,8 @@ impl BTreeMap { /// # Examples /// /// ``` - /// # #![feature(btree_range, collections_bound)] + /// #![feature(btree_range, collections_bound)] + /// /// use std::collections::BTreeMap; /// use std::collections::Bound::{Included, Excluded}; /// diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 7c4cda305a..596312e509 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -141,7 +141,8 @@ impl BTreeSet { /// # Examples /// /// ``` - /// # #![feature(btree_range, collections_bound)] + /// #![feature(btree_range, collections_bound)] + /// /// use std::collections::BTreeSet; /// use std::collections::Bound::{Included, Unbounded}; /// diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 72d0ca8535..b6c4905e41 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -85,9 +85,9 @@ //! format!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b" //! ``` //! -//! It is illegal to put positional parameters (those without names) after -//! arguments which have names. Like with positional parameters, it is illegal -//! to provide named parameters that are unused by the format string. +//! It is not valid to put positional parameters (those without names) after +//! arguments which have names. Like with positional parameters, it is not +//! valid to provide named parameters that are unused by the format string. //! //! ## Argument types //! @@ -103,8 +103,9 @@ //! hexadecimal as well as an //! octal. //! -//! There are various parameters which do require a particular type, however. Namely, the `{:.*}` -//! syntax, which sets the number of numbers after the decimal in floating-point types: +//! There are various parameters which do require a particular type, however. +//! Namely, the `{:.*}` syntax, which sets the number of numbers after the +//! decimal in floating-point types: //! //! ``` //! let formatted_number = format!("{:.*}", 2, 1.234567); @@ -112,10 +113,11 @@ //! assert_eq!("1.23", formatted_number) //! ``` //! -//! If this syntax is used, then the number of characters to print precedes the actual object being -//! formatted, and the number of characters must have the type `usize`. Although a `usize` can be -//! printed with `{}`, it is illegal to reference an argument as such. For example this is another -//! invalid format string: +//! If this syntax is used, then the number of characters to print precedes the +//! actual object being formatted, and the number of characters must have the +//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to +//! reference an argument as such. For example this is another invalid format +//! string: //! //! ```text //! {:.*} {0} @@ -128,15 +130,15 @@ //! This allows multiple actual types to be formatted via `{:x}` (like `i8` as //! well as `isize`). The current mapping of types to traits is: //! -//! * *nothing* ⇒ `Display` -//! * `?` ⇒ `Debug` -//! * `o` ⇒ `Octal` -//! * `x` ⇒ `LowerHex` -//! * `X` ⇒ `UpperHex` -//! * `p` ⇒ `Pointer` -//! * `b` ⇒ `Binary` -//! * `e` ⇒ `LowerExp` -//! * `E` ⇒ `UpperExp` +//! * *nothing* ⇒ [`Display`](trait.Display.html) +//! * `?` ⇒ [`Debug`](trait.Debug.html) +//! * `o` ⇒ [`Octal`](trait.Octal.html) +//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html) +//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html) +//! * `p` ⇒ [`Pointer`](trait.Pointer.html) +//! * `b` ⇒ [`Binary`](trait.Binary.html) +//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html) +//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html) //! //! What this means is that any type of argument which implements the //! `fmt::Binary` trait can then be formatted with `{:b}`. Implementations @@ -172,7 +174,7 @@ //! like: //! //! ``` -//! # #![feature(fmt_flags)] +//! #![feature(fmt_flags)] //! use std::fmt; //! //! #[derive(Debug)] @@ -367,11 +369,11 @@ //! should always be printed. //! * '-' - Currently not used //! * '#' - This flag is indicates that the "alternate" form of printing should -//! be used. For array slices, the alternate form omits the brackets. -//! For the integer formatting traits, the alternate forms are: +//! be used. The alternate forms are: +//! * `#?` - pretty-print the `Debug` formatting //! * `#x` - precedes the argument with a "0x" //! * `#X` - precedes the argument with a "0x" -//! * `#t` - precedes the argument with a "0b" +//! * `#b` - precedes the argument with a "0b" //! * `#o` - precedes the argument with a "0o" //! * '0' - This is used to indicate for integer formats that the padding should //! both be done with a `0` character as well as be sign-aware. A format @@ -408,19 +410,20 @@ //! //! There are three possible ways to specify the desired `precision`: //! -//! There are three possible ways to specify the desired `precision`: -//! 1. An integer `.N`, -//! 2. an integer followed by dollar sign `.N$`, or -//! 3. an asterisk `.*`. +//! 1. An integer `.N`: +//! +//! the integer `N` itself is the precision. +//! +//! 2. An integer followed by dollar sign `.N$`: //! -//! The first specification, `.N`, means the integer `N` itself is the precision. +//! use format *argument* `N` (which must be a `usize`) as the precision. //! -//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision. +//! 3. An asterisk `.*`: //! -//! Finally, `.*` means that this `{...}` is associated with *two* format inputs rather than one: -//! the first input holds the `usize` precision, and the second holds the value to print. Note -//! that in this case, if one uses the format string `{:.*}`, then the `` part -//! refers to the *value* to print, and the `precision` must come in the input preceding ``. +//! `.*` means that this `{...}` is associated with *two* format inputs rather than one: the +//! first input holds the `usize` precision, and the second holds the value to print. Note that +//! in this case, if one uses the format string `{:.*}`, then the `` part refers +//! to the *value* to print, and the `precision` must come in the input preceding ``. //! //! For example, these: //! diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 8d0f57de4c..ee7d2c4d23 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -32,7 +32,6 @@ #![feature(alloc)] #![feature(box_patterns)] -#![feature(box_raw)] #![feature(box_syntax)] #![feature(core)] #![feature(core_intrinsics)] @@ -77,7 +76,9 @@ extern crate alloc; #[cfg(test)] extern crate test; pub use binary_heap::BinaryHeap; +#[allow(deprecated)] pub use bit_vec::BitVec; +#[allow(deprecated)] pub use bit_set::BitSet; pub use btree_map::BTreeMap; pub use btree_set::BTreeSet; @@ -86,6 +87,7 @@ pub use enum_set::EnumSet; pub use vec_deque::VecDeque; pub use string::String; pub use vec::Vec; +#[allow(deprecated)] pub use vec_map::VecMap; // Needed for the vec! macro @@ -107,15 +109,18 @@ pub mod str; pub mod string; pub mod vec; pub mod vec_deque; +#[allow(deprecated)] pub mod vec_map; #[unstable(feature = "bitvec", reason = "RFC 509")] pub mod bit_vec { + #![allow(deprecated)] pub use bit::{BitVec, Iter}; } #[unstable(feature = "bitset", reason = "RFC 509")] pub mod bit_set { + #![allow(deprecated)] pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference}; pub use bit::SetIter as Iter; } @@ -130,12 +135,6 @@ pub mod btree_set { pub use btree::set::*; } - -// FIXME(#14344) this shouldn't be necessary -#[doc(hidden)] -#[unstable(feature = "issue_14344_fixme")] -pub fn fixme_14344_be_sure_to_link_to_collections() {} - #[cfg(not(test))] mod std { pub use core::ops; // RangeFull diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index a02cb44896..32d6b3b95a 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -784,7 +784,8 @@ impl<'a, A> IterMut<'a, A> { /// # Examples /// /// ``` - /// # #![feature(linked_list_extras)] + /// #![feature(linked_list_extras)] + /// /// use std::collections::LinkedList; /// /// let mut list: LinkedList<_> = vec![1, 3, 4].into_iter().collect(); @@ -812,7 +813,8 @@ impl<'a, A> IterMut<'a, A> { /// # Examples /// /// ``` - /// # #![feature(linked_list_extras)] + /// #![feature(linked_list_extras)] + /// /// use std::collections::LinkedList; /// /// let mut list: LinkedList<_> = vec![1, 2, 3].into_iter().collect(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d49463911e..5ccf3973c2 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities for slice manipulation +//! A dynamically-sized view into a contiguous sequence, `[T]`. //! -//! The `slice` module contains useful code to help work with slice values. //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,7 +77,8 @@ //! iterators. //! * Further methods that return iterators are `.split()`, `.splitn()`, //! `.chunks()`, `.windows()` and more. -#![doc(primitive = "slice")] +//! +//! *[See also the slice primitive type](../primitive.slice.html).* #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -282,34 +282,65 @@ impl [T] { /// Returns all but the first element of a slice. #[unstable(feature = "slice_extras", reason = "likely to be renamed")] + #[deprecated(since = "1.3.0", reason = "superseded by split_first")] #[inline] pub fn tail(&self) -> &[T] { core_slice::SliceExt::tail(self) } + /// Returns the first and all the rest of the elements of a slice. + #[unstable(feature = "slice_splits", reason = "new API")] + #[inline] + pub fn split_first(&self) -> Option<(&T, &[T])> { + core_slice::SliceExt::split_first(self) + } + /// Returns all but the first element of a mutable slice - #[unstable(feature = "slice_extras", - reason = "likely to be renamed or removed")] + #[unstable(feature = "slice_extras", reason = "likely to be renamed or removed")] + #[deprecated(since = "1.3.0", reason = "superseded by split_first_mut")] #[inline] pub fn tail_mut(&mut self) -> &mut [T] { core_slice::SliceExt::tail_mut(self) } + /// Returns the first and all the rest of the elements of a slice. + #[unstable(feature = "slice_splits", reason = "new API")] + #[inline] + pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + core_slice::SliceExt::split_first_mut(self) + } + /// Returns all but the last element of a slice. #[unstable(feature = "slice_extras", reason = "likely to be renamed")] + #[deprecated(since = "1.3.0", reason = "superseded by split_last")] #[inline] pub fn init(&self) -> &[T] { core_slice::SliceExt::init(self) } + /// Returns the last and all the rest of the elements of a slice. + #[unstable(feature = "slice_splits", reason = "new API")] + #[inline] + pub fn split_last(&self) -> Option<(&T, &[T])> { + core_slice::SliceExt::split_last(self) + + } + /// Returns all but the last element of a mutable slice - #[unstable(feature = "slice_extras", - reason = "likely to be renamed or removed")] + #[unstable(feature = "slice_extras", reason = "likely to be renamed or removed")] + #[deprecated(since = "1.3.0", reason = "superseded by split_last_mut")] #[inline] pub fn init_mut(&mut self) -> &mut [T] { core_slice::SliceExt::init_mut(self) } + /// Returns the last and all the rest of the elements of a slice. + #[unstable(feature = "slice_splits", since = "1.3.0")] + #[inline] + pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + core_slice::SliceExt::split_last_mut(self) + } + /// Returns the last element of a slice, or `None` if it is empty. /// /// # Examples @@ -731,12 +762,16 @@ impl [T] { /// Find the first index containing a matching value. #[unstable(feature = "slice_position_elem")] + #[deprecated(since = "1.3.0", + reason = "less idiomatic than .iter().position()")] pub fn position_elem(&self, t: &T) -> Option where T: PartialEq { core_slice::SliceExt::position_elem(self, t) } /// Find the last index containing a matching value. #[unstable(feature = "slice_position_elem")] + #[deprecated(since = "1.3.0", + reason = "less idiomatic than .iter().rev().position()")] pub fn rposition_elem(&self, t: &T) -> Option where T: PartialEq { core_slice::SliceExt::rposition_elem(self, t) } @@ -852,7 +887,8 @@ impl [T] { /// # Examples /// /// ```rust - /// # #![feature(permutations)] + /// #![feature(permutations)] + /// /// let v = [1, 2, 3]; /// let mut perms = v.permutations(); /// @@ -864,7 +900,8 @@ impl [T] { /// Iterating through permutations one by one. /// /// ```rust - /// # #![feature(permutations)] + /// #![feature(permutations)] + /// /// let v = [1, 2, 3]; /// let mut perms = v.permutations(); /// @@ -889,7 +926,8 @@ impl [T] { /// # Example /// /// ```rust - /// # #![feature(permutations)] + /// #![feature(permutations)] + /// /// let v: &mut [_] = &mut [0, 1, 2]; /// v.next_permutation(); /// let b: &mut [_] = &mut [0, 2, 1]; @@ -914,7 +952,8 @@ impl [T] { /// # Example /// /// ```rust - /// # #![feature(permutations)] + /// #![feature(permutations)] + /// /// let v: &mut [_] = &mut [1, 0, 2]; /// v.prev_permutation(); /// let b: &mut [_] = &mut [0, 2, 1]; @@ -938,7 +977,8 @@ impl [T] { /// # Example /// /// ```rust - /// # #![feature(clone_from_slice)] + /// #![feature(clone_from_slice)] + /// /// let mut dst = [0, 0, 0]; /// let src = [1, 2]; /// @@ -969,7 +1009,8 @@ impl [T] { /// # Examples /// /// ```rust - /// # #![feature(move_from)] + /// #![feature(move_from)] + /// /// let mut a = [1, 2, 3, 4, 5]; /// let b = vec![6, 7, 8]; /// let num_moved = a.move_from(b, 0, 3); @@ -978,6 +1019,8 @@ impl [T] { /// ``` #[unstable(feature = "move_from", reason = "uncertain about this API approach")] + #[deprecated(since = "1.3.0", + reason = "unclear that it must belong in the standard library")] #[inline] pub fn move_from(&mut self, mut src: Vec, start: usize, end: usize) -> usize { for (a, b) in self.iter_mut().zip(&mut src[start .. end]) { @@ -1025,6 +1068,17 @@ pub trait SliceConcatExt { #[stable(feature = "rust1", since = "1.0.0")] fn concat(&self) -> Self::Output; + /// Flattens a slice of `T` into a single value `Self::Output`, placing a + /// given separator between each. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(["hello", "world"].join(" "), "hello world"); + /// ``` + #[stable(feature = "rename_connect_to_join", since = "1.3.0")] + fn join(&self, sep: &T) -> Self::Output; + /// Flattens a slice of `T` into a single value `Self::Output`, placing a /// given separator between each. /// @@ -1034,6 +1088,7 @@ pub trait SliceConcatExt { /// assert_eq!(["hello", "world"].connect(" "), "hello world"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.3.0", reason = "renamed to join")] fn connect(&self, sep: &T) -> Self::Output; } @@ -1049,7 +1104,7 @@ impl> SliceConcatExt for [V] { result } - fn connect(&self, sep: &T) -> Vec { + fn join(&self, sep: &T) -> Vec { let size = self.iter().fold(0, |acc, v| acc + v.borrow().len()); let mut result = Vec::with_capacity(size + self.len()); let mut first = true; @@ -1059,6 +1114,10 @@ impl> SliceConcatExt for [V] { } result } + + fn connect(&self, sep: &T) -> Vec { + self.join(sep) + } } /// An iterator that yields the element swaps needed to produce diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 5e8a9bca34..670d99bae4 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -8,43 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unicode string manipulation (the `str` type). +//! Unicode string slices //! -//! Rust's `str` type is one of the core primitive types of the language. `&str` -//! is the borrowed string type. This type of string can only be created from -//! other strings, unless it is a `&'static str` (see below). It is not possible -//! to move out of borrowed strings because they are owned elsewhere. -//! -//! # Examples -//! -//! Here's some code that uses a `&str`: -//! -//! ``` -//! let s = "Hello, world."; -//! ``` -//! -//! This `&str` is a `&'static str`, which is the type of string literals. -//! They're `'static` because literals are available for the entire lifetime of -//! the program. -//! -//! You can get a non-`'static` `&str` by taking a slice of a `String`: -//! -//! ``` -//! let some_string = "Hello, world.".to_string(); -//! let s = &some_string; -//! ``` -//! -//! # Representation -//! -//! Rust's string type, `str`, is a sequence of Unicode scalar values encoded as -//! a stream of UTF-8 bytes. All [strings](../../reference.html#literals) are -//! guaranteed to be validly encoded UTF-8 sequences. Additionally, strings are -//! not null-terminated and can thus contain null bytes. -//! -//! The actual representation of `str`s have direct mappings to slices: `&str` -//! is the same as `&[u8]`. +//! *[See also the `str` primitive type](../primitive.str.html).* + -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -61,6 +29,7 @@ use core::result::Result; use core::str as core_str; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; +use core::mem; use rustc_unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; @@ -69,6 +38,7 @@ use string::String; use rustc_unicode; use vec::Vec; use slice::SliceConcatExt; +use boxed::Box; pub use core::str::{FromStr, Utf8Error}; pub use core::str::{Lines, LinesAny, CharRange}; @@ -82,10 +52,6 @@ pub use core::str::{from_utf8_unchecked, ParseBoolError}; pub use rustc_unicode::str::{SplitWhitespace, Words, Graphemes, GraphemeIndices}; pub use core::str::pattern; -/* -Section: Creating a string -*/ - impl> SliceConcatExt for [S] { type Output = String; @@ -105,7 +71,7 @@ impl> SliceConcatExt for [S] { result } - fn connect(&self, sep: &str) -> String { + fn join(&self, sep: &str) -> String { if self.is_empty() { return String::new(); } @@ -132,11 +98,11 @@ impl> SliceConcatExt for [S] { } result } -} -/* -Section: Iterators -*/ + fn connect(&self, sep: &str) -> String { + self.join(sep) + } +} // Helper functions used for Unicode normalization fn canonical_sort(comb: &mut [(char, u8)]) { @@ -382,10 +348,6 @@ impl<'a> Iterator for Utf16Units<'a> { fn size_hint(&self) -> (usize, Option) { self.encoder.size_hint() } } -/* -Section: Misc -*/ - // Return the initial codepoint accumulator for the first byte. // The first byte is special, only want bottom 5 bits for width 2, 4 bits // for width 3, and 3 bits for width 4 @@ -414,15 +376,6 @@ impl ToOwned for str { } } -/* -Section: CowString -*/ - -/* -Section: Trait implementations -*/ - - /// Any string that can be represented as a slice. #[lang = "str"] #[cfg(not(test))] @@ -472,6 +425,7 @@ impl str { since = "1.0.0")] #[unstable(feature = "unicode", reason = "this functionality may only be provided by libunicode")] + #[inline] pub fn width(&self, is_cjk: bool) -> usize { UnicodeStr::width(self, is_cjk) } @@ -483,14 +437,13 @@ impl str { /// considered to be /// boundaries. /// - /// # Panics - /// - /// Panics if `index` is greater than `self.len()`. + /// Returns `false` if `index` is greater than `self.len()`. /// /// # Examples /// /// ``` - /// # #![feature(str_char)] + /// #![feature(str_char)] + /// /// let s = "Löwe 老虎 Léopard"; /// assert!(s.is_char_boundary(0)); /// // start of `老` @@ -508,6 +461,7 @@ impl str { with the existence of the char_indices iterator or \ this method may want to be replaced with checked \ slicing")] + #[inline] pub fn is_char_boundary(&self, index: usize) -> bool { core_str::StrExt::is_char_boundary(self, index) } @@ -549,7 +503,7 @@ impl str { /// /// # Unsafety /// - /// Caller must check both UTF-8 character boundaries and the boundaries + /// Caller must check both UTF-8 sequence boundaries and the boundaries /// of the entire slice as /// well. /// @@ -563,19 +517,30 @@ impl str { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { core_str::StrExt::slice_unchecked(self, begin, end) } - /// Returns a slice of the string from the character range [`begin`..`end`). + /// Takes a bytewise mutable slice from a string. + /// + /// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`. + #[unstable(feature = "str_slice_mut", reason = "recently added")] + #[inline] + pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + core_str::StrExt::slice_mut_unchecked(self, begin, end) + } + + /// Returns a slice of the string from the range [`begin`..`end`) where indices + /// are counted in code points. /// /// That is, start at the `begin`-th code point of the string and continue /// to the `end`-th code point. This does not detect or handle edge cases - /// such as leaving a combining character as the first code point of the + /// such as leaving a combining character as the first `char` of the /// string. /// /// Due to the design of UTF-8, this operation is `O(end)`. Use slicing - /// syntax if you want to use byte indices rather than codepoint indices. + /// syntax if you want to use `O(1)` byte indices instead. /// /// # Panics /// @@ -585,7 +550,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(slice_chars)] + /// #![feature(slice_chars)] + /// /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.slice_chars(0, 4), "Löwe"); @@ -593,30 +559,35 @@ impl str { /// ``` #[unstable(feature = "slice_chars", reason = "may have yet to prove its worth")] + #[deprecated(since = "1.3.0", + reason = "can be implemented with char_indices and \ + hasn't seen enough use to justify inclusion")] + #[inline] pub fn slice_chars(&self, begin: usize, end: usize) -> &str { core_str::StrExt::slice_chars(self, begin, end) } - /// Given a byte position, return the next char and its index. + /// Given a byte position, return the next code point and its index. /// - /// This can be used to iterate over the Unicode characters of a string. + /// This can be used to iterate over the Unicode code points of a string. /// /// # Panics /// /// If `i` is greater than or equal to the length of the string. - /// If `i` is not the index of the beginning of a valid UTF-8 character. + /// If `i` is not the index of the beginning of a valid UTF-8 sequence. /// /// # Examples /// - /// This example manually iterates through the characters of a string; + /// This example manually iterates through the code points of a string; /// this should normally be /// done by `.chars()` or `.char_indices()`. /// /// ``` - /// # #![feature(str_char, core)] + /// #![feature(str_char, core)] + /// /// use std::str::CharRange; /// - /// let s = "中华Việt Nam"; + /// let s = "中华Việt Nam"; /// let mut i = 0; /// while i < s.len() { /// let CharRange {ch, next} = s.char_range_at(i); @@ -632,43 +603,50 @@ impl str { /// 3: 华 /// 6: V /// 7: i - /// 8: ệ - /// 11: t - /// 12: - /// 13: N - /// 14: a - /// 15: m + /// 8: e + /// 9: Ì£ + /// 11: ̂ + /// 13: t + /// 14: + /// 15: N + /// 16: a + /// 17: m /// ``` #[unstable(feature = "str_char", reason = "often replaced by char_indices, this method may \ be removed in favor of just char_at() or eventually \ removed altogether")] + #[inline] pub fn char_range_at(&self, start: usize) -> CharRange { core_str::StrExt::char_range_at(self, start) } /// Given a byte position, return the previous `char` and its position. /// - /// This function can be used to iterate over a Unicode string in reverse. + /// This function can be used to iterate over a Unicode code points in reverse. + /// + /// Note that Unicode has many features, such as combining marks, ligatures, + /// and direction marks, that need to be taken into account to correctly reverse a string. /// /// Returns 0 for next index if called on start index 0. /// /// # Panics /// /// If `i` is greater than the length of the string. - /// If `i` is not an index following a valid UTF-8 character. + /// If `i` is not an index following a valid UTF-8 sequence. /// /// # Examples /// - /// This example manually iterates through the characters of a string; + /// This example manually iterates through the code points of a string; /// this should normally be /// done by `.chars().rev()` or `.char_indices()`. /// /// ``` - /// # #![feature(str_char, core)] + /// #![feature(str_char, core)] + /// /// use std::str::CharRange; /// - /// let s = "中华Việt Nam"; + /// let s = "中华Việt Nam"; /// let mut i = s.len(); /// while i > 0 { /// let CharRange {ch, next} = s.char_range_at_reverse(i); @@ -680,12 +658,14 @@ impl str { /// This outputs: /// /// ```text - /// 16: m - /// 15: a - /// 14: N - /// 13: - /// 12: t - /// 11: ệ + /// 18: m + /// 17: a + /// 16: N + /// 15: + /// 14: t + /// 13: ̂ + /// 11: Ì£ + /// 9: e /// 8: i /// 7: V /// 6: 华 @@ -695,6 +675,7 @@ impl str { reason = "often replaced by char_indices, this method may \ be removed in favor of just char_at_reverse() or \ eventually removed altogether")] + #[inline] pub fn char_range_at_reverse(&self, start: usize) -> CharRange { core_str::StrExt::char_range_at_reverse(self, start) } @@ -704,15 +685,17 @@ impl str { /// # Panics /// /// If `i` is greater than or equal to the length of the string. - /// If `i` is not the index of the beginning of a valid UTF-8 character. + /// If `i` is not the index of the beginning of a valid UTF-8 sequence. /// /// # Examples /// /// ``` - /// # #![feature(str_char)] + /// #![feature(str_char)] + /// /// let s = "abπc"; /// assert_eq!(s.char_at(1), 'b'); /// assert_eq!(s.char_at(2), 'π'); + /// assert_eq!(s.char_at(4), 'c'); /// ``` #[unstable(feature = "str_char", reason = "frequently replaced by the chars() iterator, this \ @@ -720,6 +703,7 @@ impl str { future; it is normally replaced by chars/char_indices \ iterators or by getting the first char from a \ subslice")] + #[inline] pub fn char_at(&self, i: usize) -> char { core_str::StrExt::char_at(self, i) } @@ -730,51 +714,58 @@ impl str { /// # Panics /// /// If `i` is greater than the length of the string. - /// If `i` is not an index following a valid UTF-8 character. + /// If `i` is not an index following a valid UTF-8 sequence. /// /// # Examples /// /// ``` - /// # #![feature(str_char)] + /// #![feature(str_char)] + /// /// let s = "abπc"; /// assert_eq!(s.char_at_reverse(1), 'a'); /// assert_eq!(s.char_at_reverse(2), 'b'); + /// assert_eq!(s.char_at_reverse(3), 'π'); /// ``` #[unstable(feature = "str_char", reason = "see char_at for more details, but reverse semantics \ are also somewhat unclear, especially with which \ cases generate panics")] + #[inline] pub fn char_at_reverse(&self, i: usize) -> char { core_str::StrExt::char_at_reverse(self, i) } - /// Retrieves the first character from a `&str` and returns it. + /// Retrieves the first code point from a `&str` and returns it. + /// + /// Note that a single Unicode character (grapheme cluster) + /// can be composed of multiple `char`s. /// /// This does not allocate a new string; instead, it returns a slice that - /// points one character - /// beyond the character that was shifted. + /// points one code point beyond the code point that was shifted. /// - /// If the slice does not contain any characters, None is returned instead. + /// `None` is returned if the slice is empty. /// /// # Examples /// /// ``` - /// # #![feature(str_char)] - /// let s = "Löwe 老虎 Léopard"; + /// #![feature(str_char)] + /// + /// let s = "Łódź"; // \u{141}o\u{301}dz\u{301} /// let (c, s1) = s.slice_shift_char().unwrap(); /// - /// assert_eq!(c, 'L'); - /// assert_eq!(s1, "öwe 老虎 Léopard"); + /// assert_eq!(c, 'Ł'); + /// assert_eq!(s1, "ódź"); /// /// let (c, s2) = s1.slice_shift_char().unwrap(); /// - /// assert_eq!(c, 'ö'); - /// assert_eq!(s2, "we 老虎 Léopard"); + /// assert_eq!(c, 'o'); + /// assert_eq!(s2, "\u{301}dz\u{301}"); /// ``` #[unstable(feature = "str_char", reason = "awaiting conventions about shifting and slices and \ may not be warranted with the existence of the chars \ and/or char_indices iterators")] + #[inline] pub fn slice_shift_char(&self) -> Option<(char, &str)> { core_str::StrExt::slice_shift_char(self) } @@ -782,18 +773,19 @@ impl str { /// Divide one string slice into two at an index. /// /// The index `mid` is a byte offset from the start of the string - /// that must be on a character boundary. + /// that must be on a `char` boundary. /// /// Return slices `&self[..mid]` and `&self[mid..]`. /// /// # Panics /// - /// Panics if `mid` is beyond the last character of the string, - /// or if it is not on a character boundary. + /// Panics if `mid` is beyond the last code point of the string, + /// or if it is not on a `char` boundary. /// /// # Examples /// ``` - /// # #![feature(collections)] + /// #![feature(str_split_at)] + /// /// let s = "Löwe 老虎 Léopard"; /// let first_space = s.find(' ').unwrap_or(s.len()); /// let (a, b) = s.split_at(first_space); @@ -802,35 +794,57 @@ impl str { /// assert_eq!(b, " 老虎 Léopard"); /// ``` #[inline] + #[unstable(feature = "str_split_at", reason = "recently added")] pub fn split_at(&self, mid: usize) -> (&str, &str) { core_str::StrExt::split_at(self, mid) } - /// An iterator over the codepoints of `self`. + /// Divide one mutable string slice into two at an index. + #[inline] + #[unstable(feature = "str_split_at", reason = "recently added")] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + core_str::StrExt::split_at_mut(self, mid) + } + + /// An iterator over the code points of `self`. + /// + /// In Unicode relationship between code points and characters is complex. + /// A single character may be composed of multiple code points + /// (e.g. diacritical marks added to a letter), and a single code point + /// (e.g. Hangul syllable) may contain multiple characters. + /// + /// For iteration over human-readable characters a grapheme cluster iterator + /// may be more appropriate. See the [unicode-segmentation crate][1]. + /// + /// [1]: https://crates.io/crates/unicode-segmentation /// /// # Examples /// /// ``` - /// let v: Vec = "abc åäö".chars().collect(); + /// let v: Vec = "ASCII żółć 🇨🇭 한".chars().collect(); /// - /// assert_eq!(v, ['a', 'b', 'c', ' ', 'Ã¥', 'ä', 'ö']); + /// assert_eq!(v, ['A', 'S', 'C', 'I', 'I', ' ', + /// 'z', '\u{307}', 'o', '\u{301}', 'ł', 'c', '\u{301}', ' ', + /// '\u{1f1e8}', '\u{1f1ed}', ' ', '한']); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn chars(&self) -> Chars { core_str::StrExt::chars(self) } - /// An iterator over the characters of `self` and their byte offsets. + /// An iterator over the `char`s of `self` and their byte offsets. /// /// # Examples /// /// ``` - /// let v: Vec<(usize, char)> = "abc".char_indices().collect(); - /// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')]; + /// let v: Vec<(usize, char)> = "A🇨🇭".char_indices().collect(); + /// let b = vec![(0, 'A'), (1, '\u{1f1e8}'), (5, '\u{1f1ed}')]; /// /// assert_eq!(v, b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn char_indices(&self) -> CharIndices { core_str::StrExt::char_indices(self) } @@ -845,6 +859,7 @@ impl str { /// assert_eq!(v, b"bors".to_vec()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn bytes(&self) -> Bytes { core_str::StrExt::bytes(self) } @@ -855,12 +870,13 @@ impl str { /// # Examples /// /// ``` - /// let some_words = " Mary had\ta little \n\t lamb"; + /// let some_words = " Mary had\ta\u{2009}little \n\t lamb"; /// let v: Vec<&str> = some_words.split_whitespace().collect(); /// /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); /// ``` #[stable(feature = "split_whitespace", since = "1.1.0")] + #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { UnicodeStr::split_whitespace(self) } @@ -871,9 +887,10 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(str_words)] - /// # #![allow(deprecated)] - /// let some_words = " Mary had\ta little \n\t lamb"; + /// #![feature(str_words)] + /// #![allow(deprecated)] + /// + /// let some_words = " Mary had\ta\u{2009}little \n\t lamb"; /// let v: Vec<&str> = some_words.words().collect(); /// /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); @@ -883,6 +900,7 @@ impl str { #[unstable(feature = "str_words", reason = "the precise algorithm to use is unclear")] #[allow(deprecated)] + #[inline] pub fn words(&self) -> Words { UnicodeStr::words(self) } @@ -909,6 +927,7 @@ impl str { /// assert_eq!(v, ["foo", "bar", "", "baz"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn lines(&self) -> Lines { core_str::StrExt::lines(self) } @@ -936,6 +955,7 @@ impl str { /// assert_eq!(v, ["foo", "bar", "", "baz"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn lines_any(&self) -> LinesAny { core_str::StrExt::lines_any(self) } @@ -1027,7 +1047,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(unicode, core)] + /// #![feature(unicode, core)] + /// /// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::>(); /// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"]; /// @@ -1053,7 +1074,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(unicode, core)] + /// #![feature(unicode, core)] + /// /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::>(); /// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]; /// @@ -1591,7 +1613,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(str_match_indices)] + /// #![feature(str_match_indices)] + /// /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect(); /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]); /// @@ -1635,7 +1658,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(str_match_indices)] + /// #![feature(str_match_indices)] + /// /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]); /// @@ -1665,7 +1689,8 @@ impl str { /// # Examples /// /// ``` - /// # #![feature(subslice_offset)] + /// #![feature(subslice_offset)] + /// /// let string = "a\nb\nc"; /// let lines: Vec<&str> = string.lines().collect(); /// @@ -1675,6 +1700,8 @@ impl str { /// ``` #[unstable(feature = "subslice_offset", reason = "awaiting convention about comparability of arbitrary slices")] + #[deprecated(since = "1.3.0", + reason = "replaced with other pattern-related methods")] pub fn subslice_offset(&self, inner: &str) -> usize { core_str::StrExt::subslice_offset(self, inner) } @@ -1859,8 +1886,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_casing)] - /// /// let s = "HELLO"; /// assert_eq!(s.to_lowercase(), "hello"); /// ``` @@ -1905,8 +1930,6 @@ impl str { /// # Examples /// /// ``` - /// #![feature(str_casing)] - /// /// let s = "hello"; /// assert_eq!(s.to_uppercase(), "HELLO"); /// ``` @@ -1930,4 +1953,14 @@ impl str { pub fn escape_unicode(&self) -> String { self.chars().flat_map(|c| c.escape_unicode()).collect() } + + /// Converts the `Box` into a `String` without copying or allocating. + #[unstable(feature = "box_str", + reason = "recently added, matches RFC")] + pub fn into_string(self: Box) -> String { + unsafe { + let slice = mem::transmute::, Box<[u8]>>(self); + String::from_utf8_unchecked(slice.into_vec()) + } + } } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 6e37a5731b..0b441b42cd 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -28,7 +28,8 @@ use rustc_unicode::str::Utf16Item; use borrow::{Cow, IntoCow}; use range::RangeArgument; use str::{self, FromStr, Utf8Error, Chars}; -use vec::{DerefVec, Vec, as_vec}; +use vec::Vec; +use boxed::Box; /// A growable string stored as a UTF-8 encoded buffer. #[derive(Clone, PartialOrd, Eq, Ord)] @@ -88,7 +89,8 @@ impl String { /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// let s = String::from("hello"); /// assert_eq!(&s[..], "hello"); /// ``` @@ -317,9 +319,14 @@ impl String { /// Creates a new `String` from a length, capacity, and pointer. /// - /// This is unsafe because: + /// # Unsafety + /// + /// This is _very_ unsafe because: /// - /// * We call `Vec::from_raw_parts` to get a `Vec`; + /// * We call `Vec::from_raw_parts` to get a `Vec`. Therefore, this + /// function inherits all of its unsafety, see [its + /// documentation](../vec/struct.Vec.html#method.from_raw_parts) + /// for the invariants it expects, they also apply to this function. /// * We assume that the `Vec` contains valid UTF-8. #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -696,7 +703,7 @@ impl String { /// # Examples /// /// ``` - /// # #![feature(drain)] + /// #![feature(drain)] /// /// let mut s = String::from("α is alpha, β is beta"); /// let beta_offset = s.find('β').unwrap_or(s.len()); @@ -736,6 +743,16 @@ impl String { string: self_ptr, } } + + /// Converts the string into `Box`. + /// + /// Note that this will drop any excess capacity. + #[unstable(feature = "box_str", + reason = "recently added, matches RFC")] + pub fn into_boxed_slice(self) -> Box { + let slice = self.vec.into_boxed_slice(); + unsafe { mem::transmute::, Box>(slice) } + } } impl FromUtf8Error { @@ -963,6 +980,35 @@ impl ops::Index for String { } } +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut> for String { + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { + &mut self[..][index] + } +} +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::IndexMut for String { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { + unsafe { mem::transmute(&mut *self.vec) } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for String { type Target = str; @@ -973,49 +1019,14 @@ impl ops::Deref for String { } } -/// Wrapper type providing a `&String` reference via `Deref`. -#[unstable(feature = "collections")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -#[allow(deprecated)] -pub struct DerefString<'a> { - x: DerefVec<'a, u8> -} - -#[allow(deprecated)] -impl<'a> Deref for DerefString<'a> { - type Target = String; - +#[stable(feature = "derefmut_for_string", since = "1.2.0")] +impl ops::DerefMut for String { #[inline] - fn deref<'b>(&'b self) -> &'b String { - unsafe { mem::transmute(&*self.x) } + fn deref_mut(&mut self) -> &mut str { + unsafe { mem::transmute(&mut self.vec[..]) } } } -/// Converts a string slice to a wrapper type providing a `&String` reference. -/// -/// # Examples -/// -/// ``` -/// # #![feature(collections)] -/// use std::string::as_string; -/// -/// // Let's pretend we have a function that requires `&String` -/// fn string_consumer(s: &String) { -/// assert_eq!(s, "foo"); -/// } -/// -/// // Provide a `&String` from a `&str` without allocating -/// string_consumer(&as_string("foo")); -/// ``` -#[unstable(feature = "collections")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -#[allow(deprecated)] -pub fn as_string<'a>(x: &'a str) -> DerefString<'a> { - DerefString { x: as_vec(x.as_bytes()) } -} - /// Error returned from `String::from` #[unstable(feature = "str_parse_error", reason = "may want to be replaced with \ Void if it ever exists")] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 4ea26509fd..96ad00597f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -59,32 +59,25 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::prelude::*; - +use alloc::raw_vec::RawVec; use alloc::boxed::Box; -use alloc::heap::{EMPTY, allocate, reallocate, deallocate}; -use core::cmp::max; +use alloc::heap::EMPTY; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; -use core::intrinsics::{arith_offset, assume}; -use core::iter::{repeat, FromIterator}; +use core::intrinsics::{arith_offset, assume, drop_in_place}; +use core::iter::FromIterator; use core::marker::PhantomData; use core::mem; use core::ops::{Index, IndexMut, Deref}; use core::ops; use core::ptr; -use core::ptr::Unique; use core::slice; -use core::isize; -use core::usize; use borrow::{Cow, IntoCow}; use super::range::RangeArgument; -// FIXME- fix places which assume the max vector allowed has memory usize::MAX. -const MAX_MEMORY_SIZE: usize = isize::MAX as usize; - /// A growable list type, written `Vec` but pronounced 'vector.' /// /// # Examples @@ -119,6 +112,13 @@ const MAX_MEMORY_SIZE: usize = isize::MAX as usize; /// assert_eq!(vec, [1, 2, 3, 4]); /// ``` /// +/// It can also initialize each element of a `Vec` with a given value: +/// +/// ``` +/// let vec = vec![0; 5]; +/// assert_eq!(vec, [0, 0, 0, 0, 0]); +/// ``` +/// /// Use a `Vec` as an efficient stack: /// /// ``` @@ -152,14 +152,10 @@ const MAX_MEMORY_SIZE: usize = isize::MAX as usize; #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Vec { - ptr: Unique, + buf: RawVec, len: usize, - cap: usize, } -unsafe impl Send for Vec { } -unsafe impl Sync for Vec { } - //////////////////////////////////////////////////////////////////////////////// // Inherent methods //////////////////////////////////////////////////////////////////////////////// @@ -177,11 +173,7 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Vec { - // We want ptr to never be NULL so instead we set it to some arbitrary - // non-null value which is fine since we never call deallocate on the ptr - // if cap is 0. The reason for this is because the pointer of a slice - // being NULL would break the null pointer optimization for enums. - unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, 0) } + Vec { buf: RawVec::new(), len: 0 } } /// Constructs a new, empty `Vec` with the specified capacity. @@ -212,22 +204,23 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> Vec { - if mem::size_of::() == 0 { - unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, usize::MAX) } - } else if capacity == 0 { - Vec::new() - } else { - let size = capacity.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - let ptr = unsafe { allocate(size, mem::align_of::()) }; - if ptr.is_null() { ::alloc::oom() } - unsafe { Vec::from_raw_parts(ptr as *mut T, 0, capacity) } - } + Vec { buf: RawVec::with_capacity(capacity), len: 0 } } /// Creates a `Vec` directly from the raw components of another vector. /// - /// This is highly unsafe, due to the number of invariants that aren't checked. + /// # Unsafety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` needs to have been previously allocated via `String`/`Vec` + /// (at least, it's highly likely to be incorrect if it wasn't). + /// * `length` needs to be the length that less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal datastructures. /// /// # Examples /// @@ -263,9 +256,8 @@ impl Vec { pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Vec { Vec { - ptr: Unique::new(ptr), + buf: RawVec::from_raw_parts(ptr, capacity), len: length, - cap: capacity, } } @@ -299,7 +291,7 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.cap + self.buf.cap() } /// Reserves capacity for at least `additional` more elements to be inserted @@ -319,17 +311,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - if self.cap - self.len < additional { - const ERR_MSG: &'static str = "Vec::reserve: `isize` overflow"; - - let new_min_cap = self.len.checked_add(additional).expect(ERR_MSG); - if new_min_cap > MAX_MEMORY_SIZE { panic!(ERR_MSG) } - self.grow_capacity(match new_min_cap.checked_next_power_of_two() { - Some(x) if x > MAX_MEMORY_SIZE => MAX_MEMORY_SIZE, - None => MAX_MEMORY_SIZE, - Some(x) => x, - }); - } + self.buf.reserve(self.len, additional); } /// Reserves the minimum capacity for exactly `additional` more elements to @@ -353,12 +335,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { - if self.cap - self.len < additional { - match self.len.checked_add(additional) { - None => panic!("Vec::reserve: `usize` overflow"), - Some(new_cap) => self.grow_capacity(new_cap) - } - } + self.buf.reserve_exact(self.len, additional); } /// Shrinks the capacity of the vector as much as possible. @@ -377,28 +354,7 @@ impl Vec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - if mem::size_of::() == 0 { return } - - if self.len == 0 { - if self.cap != 0 { - unsafe { - dealloc(*self.ptr, self.cap) - } - self.cap = 0; - } - } else if self.cap != self.len { - unsafe { - // Overflow check is unnecessary as the vector is already at - // least this large. - let ptr = reallocate(*self.ptr as *mut u8, - self.cap * mem::size_of::(), - self.len * mem::size_of::(), - mem::align_of::()) as *mut T; - if ptr.is_null() { ::alloc::oom() } - self.ptr = Unique::new(ptr); - } - self.cap = self.len; - } + self.buf.shrink_to_fit(self.len); } /// Converts the vector into Box<[T]>. @@ -408,11 +364,11 @@ impl Vec { /// `shrink_to_fit()`. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_boxed_slice(mut self) -> Box<[T]> { - self.shrink_to_fit(); unsafe { - let xs: Box<[T]> = Box::from_raw(&mut *self); + self.shrink_to_fit(); + let buf = ptr::read(&self.buf); mem::forget(self); - xs + buf.into_box() } } @@ -529,8 +485,9 @@ impl Vec { pub fn insert(&mut self, index: usize, element: T) { let len = self.len(); assert!(index <= len); + // space for the new element - self.reserve(1); + if len == self.buf.cap() { self.buf.double(); } unsafe { // infallible // The spot to put the new value @@ -538,10 +495,10 @@ impl Vec { let p = self.as_mut_ptr().offset(index as isize); // Shift everything over to make space. (Duplicating the // `index`th element into two consecutive places.) - ptr::copy(&*p, p.offset(1), len - index); + ptr::copy(p, p.offset(1), len - index); // Write it in, overwriting the first copy of the `index`th // element. - ptr::write(&mut *p, element); + ptr::write(p, element); } self.set_len(len + 1); } @@ -575,7 +532,7 @@ impl Vec { ret = ptr::read(ptr); // Shift everything down to fill in that spot. - ptr::copy(&*ptr.offset(1), ptr, len - index - 1); + ptr::copy(ptr.offset(1), ptr, len - index - 1); } self.set_len(len - 1); ret @@ -624,45 +581,19 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec = vec!(1, 2); + /// let mut vec = vec![1, 2]; /// vec.push(3); /// assert_eq!(vec, [1, 2, 3]); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, value: T) { - #[cold] - #[inline(never)] - fn resize(vec: &mut Vec) { - let old_size = vec.cap * mem::size_of::(); - if old_size >= MAX_MEMORY_SIZE { panic!("capacity overflow") } - let mut size = max(old_size, 2 * mem::size_of::()) * 2; - if old_size > size || size > MAX_MEMORY_SIZE { - size = MAX_MEMORY_SIZE; - } - unsafe { - let ptr = alloc_or_realloc(*vec.ptr, old_size, size); - if ptr.is_null() { ::alloc::oom() } - vec.ptr = Unique::new(ptr); - } - vec.cap = max(vec.cap, 2) * 2; - } - - if mem::size_of::() == 0 { - // zero-size types consume no memory, so we can't rely on the - // address space running out - self.len = self.len.checked_add(1).expect("length overflow"); - mem::forget(value); - return - } - - if self.len == self.cap { - resize(self); - } - + // This will panic or abort if we would allocate > isize::MAX bytes + // or if the length increment would overflow for zero-sized types. + if self.len == self.buf.cap() { self.buf.double(); } unsafe { - let end = (*self.ptr).offset(self.len as isize); - ptr::write(&mut *end, value); + let end = self.as_mut_ptr().offset(self.len as isize); + ptr::write(end, value); self.len += 1; } } @@ -698,7 +629,8 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(append)] + /// #![feature(append)] + /// /// let mut vec = vec![1, 2, 3]; /// let mut vec2 = vec![4, 5, 6]; /// vec.append(&mut vec2); @@ -709,13 +641,6 @@ impl Vec { #[unstable(feature = "append", reason = "new API, waiting for dust to settle")] pub fn append(&mut self, other: &mut Self) { - if mem::size_of::() == 0 { - // zero-size types consume no memory, so we can't rely on the - // address space running out - self.len = self.len.checked_add(other.len()).expect("length overflow"); - unsafe { other.set_len(0) } - return; - } self.reserve(other.len()); let len = self.len(); unsafe { @@ -744,7 +669,7 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(drain)] + /// #![feature(drain)] /// /// // Draining using `..` clears the whole vector. /// let mut v = vec![1, 2, 3]; @@ -842,7 +767,8 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(map_in_place)] + /// #![feature(map_in_place)] + /// /// let v = vec![0, 1, 2]; /// let w = v.map_in_place(|i| i + 3); /// assert_eq!(&w[..], &[3, 4, 5]); @@ -855,6 +781,9 @@ impl Vec { /// ``` #[unstable(feature = "map_in_place", reason = "API may change to provide stronger guarantees")] + #[deprecated(since = "1.3.0", + reason = "unclear that the API is strong enough and did \ + not proven itself")] pub fn map_in_place(self, mut f: F) -> Vec where F: FnMut(T) -> U { // FIXME: Assert statically that the types `T` and `U` have the same // size. @@ -1045,7 +974,8 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(split_off)] + /// #![feature(split_off)] + /// /// let mut vec = vec![1,2,3]; /// let vec2 = vec.split_off(1); /// assert_eq!(vec, [1]); @@ -1084,7 +1014,8 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(vec_resize)] + /// #![feature(vec_resize)] + /// /// let mut vec = vec!["hello"]; /// vec.resize(3, "world"); /// assert_eq!(vec, ["hello", "world", "world"]); @@ -1099,12 +1030,35 @@ impl Vec { let len = self.len(); if new_len > len { - self.extend(repeat(value).take(new_len - len)); + self.extend_with_element(new_len - len, value); } else { self.truncate(new_len); } } + /// Extend the vector by `n` additional clones of `value`. + fn extend_with_element(&mut self, n: usize, value: T) { + self.reserve(n); + + unsafe { + let len = self.len(); + let mut ptr = self.as_mut_ptr().offset(len as isize); + // Write all elements except the last one + for i 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); + } + + if n > 0 { + // We can write the last element directly without cloning needlessly + ptr::write(ptr, value); + self.set_len(len + n); + } + } + } + /// Appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends @@ -1113,7 +1067,8 @@ impl Vec { /// # Examples /// /// ``` - /// # #![feature(vec_push_all)] + /// #![feature(vec_push_all)] + /// /// let mut vec = vec![1]; /// vec.push_all(&[2, 3, 4]); /// assert_eq!(vec, [1, 2, 3, 4]); @@ -1244,68 +1199,12 @@ impl Vec { // Internal methods and functions //////////////////////////////////////////////////////////////////////////////// -impl Vec { - /// Reserves capacity for exactly `capacity` elements in the given vector. - /// - /// If the capacity for `self` is already equal to or greater than the - /// requested capacity, then no action is taken. - fn grow_capacity(&mut self, capacity: usize) { - if mem::size_of::() == 0 { return } - - if capacity > self.cap { - let size = capacity.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - unsafe { - let ptr = alloc_or_realloc(*self.ptr, self.cap * mem::size_of::(), size); - if ptr.is_null() { ::alloc::oom() } - self.ptr = Unique::new(ptr); - } - self.cap = capacity; - } - } -} - -// FIXME: #13996: need a way to mark the return value as `noalias` -#[inline(never)] -unsafe fn alloc_or_realloc(ptr: *mut T, old_size: usize, size: usize) -> *mut T { - if old_size == 0 { - allocate(size, mem::align_of::()) as *mut T - } else { - reallocate(ptr as *mut u8, old_size, size, mem::align_of::()) as *mut T - } -} - -#[inline] -unsafe fn dealloc(ptr: *mut T, len: usize) { - if mem::size_of::() != 0 { - deallocate(ptr as *mut u8, - len * mem::size_of::(), - mem::align_of::()) - } -} - #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { - unsafe { - let mut v = Vec::with_capacity(n); - let mut ptr = v.as_mut_ptr(); - - // Write all elements except the last one - for i in 1..n { - ptr::write(ptr, Clone::clone(&elem)); - ptr = ptr.offset(1); - v.set_len(i); // Increment the length in every step in case Clone::clone() panics - } - - if n > 0 { - // We can write the last element directly without cloning needlessly - ptr::write(ptr, elem); - v.set_len(n); - } - - v - } + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v } //////////////////////////////////////////////////////////////////////////////// @@ -1449,7 +1348,7 @@ impl ops::Deref for Vec { fn deref(&self) -> &[T] { unsafe { - let p = *self.ptr; + let p = self.buf.ptr(); assume(p != 0 as *mut T); slice::from_raw_parts(p, self.len) } @@ -1460,7 +1359,7 @@ impl ops::Deref for Vec { impl ops::DerefMut for Vec { fn deref_mut(&mut self) -> &mut [T] { unsafe { - let ptr = *self.ptr; + let ptr = self.buf.ptr(); assume(!ptr.is_null()); slice::from_raw_parts_mut(ptr, self.len) } @@ -1514,19 +1413,19 @@ impl IntoIterator for Vec { /// } /// ``` #[inline] - fn into_iter(self) -> IntoIter { + fn into_iter(mut self) -> IntoIter { unsafe { - let ptr = *self.ptr; + let ptr = self.as_mut_ptr(); assume(!ptr.is_null()); - let cap = self.cap; let begin = ptr as *const T; let end = if mem::size_of::() == 0 { arith_offset(ptr as *const i8, self.len() as isize) as *const T } else { ptr.offset(self.len() as isize) as *const T }; + let buf = ptr::read(&self.buf); mem::forget(self); - IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end } + IntoIter { buf: buf, ptr: begin, end: end } } } } @@ -1638,16 +1537,16 @@ impl Ord for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Vec { fn drop(&mut self) { - // This is (and should always remain) a no-op if the fields are - // zeroed (when moving out, because of #[unsafe_no_drop_flag]). - if self.cap != 0 && self.cap != mem::POST_DROP_USIZE { - unsafe { - for x in self.iter() { - ptr::read(x); - } - dealloc(*self.ptr, self.cap) + // NOTE: this is currently abusing the fact that ZSTs can't impl Drop. + // Or rather, that impl'ing Drop makes them not zero-sized. This is + // OK because exactly when this stops being a valid assumption, we + // don't need unsafe_no_drop_flag shenanigans anymore. + if self.buf.unsafe_no_drop_flag_needs_drop() { + for x in self.iter_mut() { + unsafe { drop_in_place(x); } } } + // RawVec handles deallocation } } @@ -1731,8 +1630,7 @@ impl<'a, T> IntoCow<'a, [T]> for &'a [T] where T: Clone { /// An iterator that moves out of a vector. #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - allocation: *mut T, // the block of memory allocated for the vector - cap: usize, // the capacity of the vector + buf: RawVec, ptr: *const T, end: *const T } @@ -1744,12 +1642,13 @@ impl IntoIter { #[inline] /// Drops all items that have not yet been moved and returns the empty vector. #[unstable(feature = "iter_to_vec")] + #[deprecated(since = "1.3.0", reason = "replaced by drain()")] pub fn into_inner(mut self) -> Vec { unsafe { for _x in self.by_ref() { } - let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self; + let buf = ptr::read(&self.buf); mem::forget(self); - Vec::from_raw_parts(allocation, 0, cap) + Vec { buf: buf, len: 0 } } } } @@ -1827,12 +1726,9 @@ impl ExactSizeIterator for IntoIter {} impl Drop for IntoIter { fn drop(&mut self) { // destroy the remaining elements - if self.cap != 0 { - for _x in self.by_ref() {} - unsafe { - dealloc(self.allocation, self.cap); - } - } + for _x in self.by_ref() {} + + // RawVec handles deallocation } } @@ -1906,73 +1802,6 @@ impl<'a, T> Drop for Drain<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Drain<'a, T> {} -//////////////////////////////////////////////////////////////////////////////// -// Conversion from &[T] to &Vec -//////////////////////////////////////////////////////////////////////////////// - -/// Wrapper type providing a `&Vec` reference via `Deref`. -#[unstable(feature = "collections")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -pub struct DerefVec<'a, T:'a> { - x: Vec, - l: PhantomData<&'a T>, -} - -#[unstable(feature = "collections")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -#[allow(deprecated)] -impl<'a, T> Deref for DerefVec<'a, T> { - type Target = Vec; - - fn deref<'b>(&'b self) -> &'b Vec { - &self.x - } -} - -// Prevent the inner `Vec` from attempting to deallocate memory. -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -#[allow(deprecated)] -impl<'a, T> Drop for DerefVec<'a, T> { - fn drop(&mut self) { - self.x.len = 0; - self.x.cap = 0; - } -} - -/// Converts a slice to a wrapper type providing a `&Vec` reference. -/// -/// # Examples -/// -/// ``` -/// # #![feature(collections)] -/// use std::vec::as_vec; -/// -/// // Let's pretend we have a function that requires `&Vec` -/// fn vec_consumer(s: &Vec) { -/// assert_eq!(s, &[1, 2, 3]); -/// } -/// -/// // Provide a `&Vec` from a `&[i32]` without allocating -/// let values = [1, 2, 3]; -/// vec_consumer(&as_vec(&values)); -/// ``` -#[unstable(feature = "collections")] -#[deprecated(since = "1.2.0", - reason = "replaced with deref coercions or Borrow")] -#[allow(deprecated)] -pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> { - unsafe { - DerefVec { - x: Vec::from_raw_parts(x.as_ptr() as *mut T, x.len(), x.len()), - l: PhantomData, - } - } -} - //////////////////////////////////////////////////////////////////////////////// // Partial vec, used for map_in_place //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index ed47c06e7c..c6d0d946ab 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -23,33 +23,35 @@ use core::prelude::*; use core::cmp::Ordering; use core::fmt; use core::iter::{self, repeat, FromIterator, RandomAccessIterator}; -use core::mem; use core::ops::{Index, IndexMut}; -use core::ptr::{self, Unique}; +use core::ptr; use core::slice; use core::hash::{Hash, Hasher}; use core::cmp; -use alloc::heap; +use alloc::raw_vec::RawVec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 /// `VecDeque` is a growable ring buffer, which can be used as a /// double-ended queue efficiently. +/// +/// The "default" usage of this type as a queue is to use `push_back` to add to the queue, and +/// `pop_front` to remove from the queue. `extend` and `append` push onto the back in this manner, +/// and iterating over `VecDeque` goes front to back. #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { // tail and head are pointers into the buffer. Tail always points // to the first element that could be read, Head always points // to where data should be written. - // If tail == head the buffer is empty. The length of the ringbuf + // If tail == head the buffer is empty. The length of the ringbuffer // is defined as the distance between the two. tail: usize, head: usize, - cap: usize, - ptr: Unique, + buf: RawVec, } #[stable(feature = "rust1", since = "1.0.0")] @@ -63,13 +65,7 @@ impl Clone for VecDeque { impl Drop for VecDeque { fn drop(&mut self) { self.clear(); - unsafe { - if mem::size_of::() != 0 { - heap::deallocate(*self.ptr as *mut u8, - self.cap * mem::size_of::(), - mem::align_of::()) - } - } + // RawVec handles deallocation } } @@ -80,78 +76,127 @@ impl Default for VecDeque { } impl VecDeque { + /// Marginally more convenient + #[inline] + fn ptr(&self) -> *mut T { + self.buf.ptr() + } + + /// Marginally more convenient + #[inline] + fn cap(&self) -> usize { + self.buf.cap() + } + /// Turn ptr into a slice #[inline] unsafe fn buffer_as_slice(&self) -> &[T] { - slice::from_raw_parts(*self.ptr, self.cap) + slice::from_raw_parts(self.ptr(), self.cap()) } /// Turn ptr into a mut slice #[inline] unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T] { - slice::from_raw_parts_mut(*self.ptr, self.cap) + slice::from_raw_parts_mut(self.ptr(), self.cap()) } /// Moves an element out of the buffer #[inline] unsafe fn buffer_read(&mut self, off: usize) -> T { - ptr::read(self.ptr.offset(off as isize)) + ptr::read(self.ptr().offset(off as isize)) } /// Writes an element into the buffer, moving it. #[inline] - unsafe fn buffer_write(&mut self, off: usize, t: T) { - ptr::write(self.ptr.offset(off as isize), t); + unsafe fn buffer_write(&mut self, off: usize, value: T) { + ptr::write(self.ptr().offset(off as isize), value); } - /// Returns true iff the buffer is at capacity + /// Returns true if and only if the buffer is at capacity #[inline] - fn is_full(&self) -> bool { self.cap - self.len() == 1 } + fn is_full(&self) -> bool { self.cap() - self.len() == 1 } /// Returns the index in the underlying buffer for a given logical element /// index. #[inline] - fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap) } + fn wrap_index(&self, idx: usize) -> usize { wrap_index(idx, self.cap()) } /// Returns the index in the underlying buffer for a given logical element /// index + addend. #[inline] fn wrap_add(&self, idx: usize, addend: usize) -> usize { - wrap_index(idx.wrapping_add(addend), self.cap) + wrap_index(idx.wrapping_add(addend), self.cap()) } /// Returns the index in the underlying buffer for a given logical element /// index - subtrahend. #[inline] fn wrap_sub(&self, idx: usize, subtrahend: usize) -> usize { - wrap_index(idx.wrapping_sub(subtrahend), self.cap) + wrap_index(idx.wrapping_sub(subtrahend), self.cap()) } /// Copies a contiguous block of memory len long from src to dst #[inline] unsafe fn copy(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); + debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + self.cap()); + debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + self.cap()); ptr::copy( - self.ptr.offset(src as isize), - self.ptr.offset(dst as isize), + self.ptr().offset(src as isize), + self.ptr().offset(dst as isize), len); } /// Copies a contiguous block of memory len long from src to dst #[inline] unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); - debug_assert!(src + len <= self.cap, "dst={} src={} len={} cap={}", dst, src, len, - self.cap); + debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + self.cap()); + debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + self.cap()); ptr::copy_nonoverlapping( - self.ptr.offset(src as isize), - self.ptr.offset(dst as isize), + self.ptr().offset(src as isize), + self.ptr().offset(dst as isize), len); } + + /// Frobs the head and tail sections around to handle the fact that we + /// just reallocated. Unsafe because it trusts old_cap. + #[inline] + unsafe fn handle_cap_increase(&mut self, old_cap: usize) { + let new_cap = self.cap(); + + // Move the shortest contiguous section of the ring buffer + // T H + // [o o o o o o o . ] + // T H + // A [o o o o o o o . . . . . . . . . ] + // H T + // [o o . o o o o o ] + // T H + // B [. . . o o o o o o o . . . . . . ] + // H T + // [o o o o o . o o ] + // H T + // C [o o o o o . . . . . . . . . o o ] + + if self.tail <= self.head { // A + // Nop + } else if self.head < old_cap - self.tail { // B + self.copy_nonoverlapping(old_cap, 0, self.head); + self.head += old_cap; + debug_assert!(self.head > self.tail); + } else { // C + let new_tail = new_cap - (old_cap - self.tail); + self.copy_nonoverlapping(new_tail, self.tail, old_cap - self.tail); + self.tail = new_tail; + debug_assert!(self.head < self.tail); + } + debug_assert!(self.head < self.cap()); + debug_assert!(self.tail < self.cap()); + debug_assert!(self.cap().count_ones() == 1); + } } impl VecDeque { @@ -167,24 +212,11 @@ impl VecDeque { // +1 since the ringbuffer always leaves one space empty let cap = cmp::max(n + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); assert!(cap > n, "capacity overflow"); - let size = cap.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - - let ptr = unsafe { - if mem::size_of::() != 0 { - let ptr = heap::allocate(size, mem::align_of::()) as *mut T;; - if ptr.is_null() { ::alloc::oom() } - Unique::new(ptr) - } else { - Unique::new(heap::EMPTY as *mut T) - } - }; VecDeque { tail: 0, head: 0, - cap: cap, - ptr: ptr, + buf: RawVec::with_capacity(cap), } } @@ -199,13 +231,13 @@ impl VecDeque { /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); - /// assert_eq!(buf.get(1).unwrap(), &4); + /// assert_eq!(buf.get(1), Some(&4)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, i: usize) -> Option<&T> { - if i < self.len() { - let idx = self.wrap_add(self.tail, i); - unsafe { Some(&*self.ptr.offset(idx as isize)) } + pub fn get(&self, index: usize) -> Option<&T> { + if index < self.len() { + let idx = self.wrap_add(self.tail, index); + unsafe { Some(&*self.ptr().offset(idx as isize)) } } else { None } @@ -229,10 +261,10 @@ impl VecDeque { /// assert_eq!(buf[1], 7); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, i: usize) -> Option<&mut T> { - if i < self.len() { - let idx = self.wrap_add(self.tail, i); - unsafe { Some(&mut *self.ptr.offset(idx as isize)) } + pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + if index < self.len() { + let idx = self.wrap_add(self.tail, index); + unsafe { Some(&mut *self.ptr().offset(idx as isize)) } } else { None } @@ -264,7 +296,7 @@ impl VecDeque { let ri = self.wrap_add(self.tail, i); let rj = self.wrap_add(self.tail, j); unsafe { - ptr::swap(self.ptr.offset(ri as isize), self.ptr.offset(rj as isize)) + ptr::swap(self.ptr().offset(ri as isize), self.ptr().offset(rj as isize)) } } @@ -281,7 +313,7 @@ impl VecDeque { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn capacity(&self) -> usize { self.cap - 1 } + pub fn capacity(&self) -> usize { self.cap() - 1 } /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the /// given `VecDeque`. Does nothing if the capacity is already sufficient. @@ -309,7 +341,7 @@ impl VecDeque { } /// Reserves capacity for at least `additional` more elements to be inserted in the given - /// `Ringbuf`. The collection may reserve more space to avoid frequent reallocations. + /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations. /// /// # Panics /// @@ -326,74 +358,29 @@ impl VecDeque { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - let new_len = self.len() + additional; - assert!(new_len + 1 > self.len(), "capacity overflow"); - if new_len > self.capacity() { - let count = (new_len + 1).next_power_of_two(); - assert!(count >= new_len + 1); - - if mem::size_of::() != 0 { - let old = self.cap * mem::size_of::(); - let new = count.checked_mul(mem::size_of::()) - .expect("capacity overflow"); - unsafe { - let ptr = heap::reallocate(*self.ptr as *mut u8, - old, - new, - mem::align_of::()) as *mut T; - if ptr.is_null() { ::alloc::oom() } - self.ptr = Unique::new(ptr); - } - } - - // Move the shortest contiguous section of the ring buffer - // T H - // [o o o o o o o . ] - // T H - // A [o o o o o o o . . . . . . . . . ] - // H T - // [o o . o o o o o ] - // T H - // B [. . . o o o o o o o . . . . . . ] - // H T - // [o o o o o . o o ] - // H T - // C [o o o o o . . . . . . . . . o o ] - - let oldcap = self.cap; - self.cap = count; - - if self.tail <= self.head { // A - // Nop - } else if self.head < oldcap - self.tail { // B - unsafe { - self.copy_nonoverlapping(oldcap, 0, self.head); - } - self.head += oldcap; - debug_assert!(self.head > self.tail); - } else { // C - let new_tail = count - (oldcap - self.tail); - unsafe { - self.copy_nonoverlapping(new_tail, self.tail, oldcap - self.tail); - } - self.tail = new_tail; - debug_assert!(self.head < self.tail); - } - debug_assert!(self.head < self.cap); - debug_assert!(self.tail < self.cap); - debug_assert!(self.cap.count_ones() == 1); + let old_cap = self.cap(); + let used_cap = self.len() + 1; + let new_cap = used_cap + .checked_add(additional) + .and_then(|needed_cap| needed_cap.checked_next_power_of_two()) + .expect("capacity overflow"); + + if new_cap > self.capacity() { + self.buf.reserve_exact(used_cap, new_cap - used_cap); + unsafe { self.handle_cap_increase(old_cap); } } } - /// Shrinks the capacity of the ringbuf as much as possible. + /// Shrinks the capacity of the `VecDeque` as much as possible. /// /// It will drop down as close as possible to the length but the allocator may still inform the - /// ringbuf that there is space for a few more elements. + /// `VecDeque` that there is space for a few more elements. /// /// # Examples /// /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::with_capacity(15); @@ -404,9 +391,9 @@ impl VecDeque { /// ``` pub fn shrink_to_fit(&mut self) { // +1 since the ringbuffer always leaves one space empty - // len + 1 can't overflow for an existing, well-formed ringbuf. + // len + 1 can't overflow for an existing, well-formed ringbuffer. let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two(); - if target_cap < self.cap { + if target_cap < self.cap() { // There are three cases of interest: // All elements are out of desired bounds // Elements are contiguous, and head is out of desired bounds @@ -444,7 +431,7 @@ impl VecDeque { // H T // [o o o o o . o o ] debug_assert!(self.wrap_sub(self.head, 1) < target_cap); - let len = self.cap - self.tail; + let len = self.cap() - self.tail; let new_tail = target_cap - len; unsafe { self.copy_nonoverlapping(new_tail, self.tail, len); @@ -453,34 +440,24 @@ impl VecDeque { debug_assert!(self.head < self.tail); } - if mem::size_of::() != 0 { - let old = self.cap * mem::size_of::(); - let new_size = target_cap * mem::size_of::(); - unsafe { - let ptr = heap::reallocate(*self.ptr as *mut u8, - old, - new_size, - mem::align_of::()) as *mut T; - if ptr.is_null() { ::alloc::oom() } - self.ptr = Unique::new(ptr); - } - } - self.cap = target_cap; - debug_assert!(self.head < self.cap); - debug_assert!(self.tail < self.cap); - debug_assert!(self.cap.count_ones() == 1); + self.buf.shrink_to_fit(target_cap); + + debug_assert!(self.head < self.cap()); + debug_assert!(self.tail < self.cap()); + debug_assert!(self.cap().count_ones() == 1); } } - /// Shortens a ringbuf, dropping excess elements from the back. + /// Shortens a `VecDeque`, dropping excess elements from the back. /// - /// If `len` is greater than the ringbuf's current length, this has no + /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. /// /// # Examples /// /// ``` - /// # #![feature(deque_extras)] + /// #![feature(deque_extras)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -606,7 +583,7 @@ impl VecDeque { /// assert_eq!(v.len(), 1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn len(&self) -> usize { count(self.tail, self.head, self.cap) } + pub fn len(&self) -> usize { count(self.tail, self.head, self.cap()) } /// Returns true if the buffer contains no elements /// @@ -629,7 +606,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(drain)] + /// #![feature(drain)] + /// /// use std::collections::VecDeque; /// /// let mut v = VecDeque::new(); @@ -793,15 +771,17 @@ impl VecDeque { /// assert_eq!(d.front(), Some(&2)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_front(&mut self, t: T) { + pub fn push_front(&mut self, value: T) { if self.is_full() { - self.reserve(1); + let old_cap = self.cap(); + self.buf.double(); + unsafe { self.handle_cap_increase(old_cap); } debug_assert!(!self.is_full()); } self.tail = self.wrap_sub(self.tail, 1); let tail = self.tail; - unsafe { self.buffer_write(tail, t); } + unsafe { self.buffer_write(tail, value); } } /// Appends an element to the back of a buffer @@ -817,15 +797,17 @@ impl VecDeque { /// assert_eq!(3, *buf.back().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn push_back(&mut self, t: T) { + pub fn push_back(&mut self, value: T) { if self.is_full() { - self.reserve(1); + let old_cap = self.cap(); + self.buf.double(); + unsafe { self.handle_cap_increase(old_cap); } debug_assert!(!self.is_full()); } let head = self.head; self.head = self.wrap_add(self.head, 1); - unsafe { self.buffer_write(head, t) } + unsafe { self.buffer_write(head, value) } } /// Removes the last element from a buffer and returns it, or `None` if @@ -858,8 +840,8 @@ impl VecDeque { self.tail <= self.head } - /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the last - /// element. + /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the + /// last element. /// /// This does not preserve ordering, but is O(1). /// @@ -868,17 +850,20 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(deque_extras)] + /// #![feature(deque_extras)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); /// assert_eq!(buf.swap_back_remove(0), None); - /// buf.push_back(5); - /// buf.push_back(99); - /// buf.push_back(15); - /// buf.push_back(20); - /// buf.push_back(10); - /// assert_eq!(buf.swap_back_remove(1), Some(99)); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// + /// assert_eq!(buf.swap_back_remove(0), Some(1)); + /// assert_eq!(buf.len(), 2); + /// assert_eq!(buf[0], 3); + /// assert_eq!(buf[1], 2); /// ``` #[unstable(feature = "deque_extras", reason = "the naming of this function may be altered")] @@ -892,7 +877,7 @@ impl VecDeque { self.pop_back() } - /// Removes an element from anywhere in the ringbuf and returns it, + /// Removes an element from anywhere in the `VecDeque` and returns it, /// replacing it with the first element. /// /// This does not preserve ordering, but is O(1). @@ -902,17 +887,20 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(deque_extras)] + /// #![feature(deque_extras)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); /// assert_eq!(buf.swap_front_remove(0), None); - /// buf.push_back(15); - /// buf.push_back(5); - /// buf.push_back(10); - /// buf.push_back(99); - /// buf.push_back(20); - /// assert_eq!(buf.swap_front_remove(3), Some(99)); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// + /// assert_eq!(buf.swap_front_remove(2), Some(3)); + /// assert_eq!(buf.len(), 2); + /// assert_eq!(buf[0], 2); + /// assert_eq!(buf[1], 1); /// ``` #[unstable(feature = "deque_extras", reason = "the naming of this function may be altered")] @@ -926,29 +914,32 @@ impl VecDeque { self.pop_front() } - /// Inserts an element at position `i` within the ringbuf. Whichever + /// Inserts an element at `index` within the `VecDeque`. Whichever /// end is closer to the insertion point will be moved to make room, /// and all the affected elements will be moved to new positions. /// /// # Panics /// - /// Panics if `i` is greater than ringbuf's length + /// Panics if `index` is greater than `VecDeque`'s length /// /// # Examples /// ``` - /// # #![feature(collections)] + /// #![feature(collections)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); /// buf.push_back(10); /// buf.push_back(12); - /// buf.insert(1,11); + /// buf.insert(1, 11); /// assert_eq!(Some(&11), buf.get(1)); /// ``` - pub fn insert(&mut self, i: usize, t: T) { - assert!(i <= self.len(), "index out of bounds"); + pub fn insert(&mut self, index: usize, value: T) { + assert!(index <= self.len(), "index out of bounds"); if self.is_full() { - self.reserve(1); + let old_cap = self.cap(); + self.buf.double(); + unsafe { self.handle_cap_increase(old_cap); } debug_assert!(!self.is_full()); } @@ -974,15 +965,15 @@ impl VecDeque { // A - The element that should be after the insertion point // M - Indicates element was moved - let idx = self.wrap_add(self.tail, i); + let idx = self.wrap_add(self.tail, index); - let distance_to_tail = i; - let distance_to_head = self.len() - i; + let distance_to_tail = index; + let distance_to_head = self.len() - index; let contiguous = self.is_contiguous(); match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) { - (true, true, _) if i == 0 => { + (true, true, _) if index == 0 => { // push_front // // T @@ -1018,8 +1009,8 @@ impl VecDeque { let new_tail = self.wrap_sub(self.tail, 1); self.copy(new_tail, self.tail, 1); - // Already moved the tail, so we only copy `i - 1` elements. - self.copy(self.tail, self.tail + 1, i - 1); + // Already moved the tail, so we only copy `index - 1` elements. + self.copy(self.tail, self.tail + 1, index - 1); self.tail = new_tail; }, @@ -1046,7 +1037,7 @@ impl VecDeque { // [o o o o o o . . . . o o I A o o] // M M - self.copy(self.tail - 1, self.tail, i); + self.copy(self.tail - 1, self.tail, index); self.tail -= 1; }, (false, false, true) => unsafe { @@ -1063,10 +1054,10 @@ impl VecDeque { self.copy(1, 0, self.head); // copy last element into empty spot at bottom of buffer - self.copy(0, self.cap - 1, 1); + self.copy(0, self.cap() - 1, 1); // move elements from idx to end forward not including ^ element - self.copy(idx + 1, idx, self.cap - 1 - idx); + self.copy(idx + 1, idx, self.cap() - 1 - idx); self.head += 1; }, @@ -1082,10 +1073,10 @@ impl VecDeque { // M M M // copy elements up to new tail - self.copy(self.tail - 1, self.tail, self.cap - self.tail); + self.copy(self.tail - 1, self.tail, self.cap() - self.tail); // copy last element into empty spot at bottom of buffer - self.copy(self.cap - 1, 0, 1); + self.copy(self.cap() - 1, 0, 1); self.tail -= 1; }, @@ -1100,10 +1091,10 @@ impl VecDeque { // M M M M M M // copy elements up to new tail - self.copy(self.tail - 1, self.tail, self.cap - self.tail); + self.copy(self.tail - 1, self.tail, self.cap() - self.tail); // copy last element into empty spot at bottom of buffer - self.copy(self.cap - 1, 0, 1); + self.copy(self.cap() - 1, 0, 1); // move elements from idx-1 to end forward not including ^ element self.copy(0, 1, idx - 1); @@ -1126,32 +1117,32 @@ impl VecDeque { } // tail might've been changed so we need to recalculate - let new_idx = self.wrap_add(self.tail, i); + let new_idx = self.wrap_add(self.tail, index); unsafe { - self.buffer_write(new_idx, t); + self.buffer_write(new_idx, value); } } - /// Removes and returns the element at position `i` from the ringbuf. + /// Removes and returns the element at `index` from the `VecDeque`. /// Whichever end is closer to the removal point will be moved to make /// room, and all the affected elements will be moved to new positions. - /// Returns `None` if `i` is out of bounds. + /// Returns `None` if `index` is out of bounds. /// /// # Examples /// ``` /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); - /// buf.push_back(5); - /// buf.push_back(10); - /// buf.push_back(12); - /// buf.push_back(15); - /// buf.remove(2); - /// assert_eq!(Some(&15), buf.get(2)); + /// buf.push_back(1); + /// buf.push_back(2); + /// buf.push_back(3); + /// + /// assert_eq!(buf.remove(1), Some(2)); + /// assert_eq!(buf.get(1), Some(&3)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, i: usize) -> Option { - if self.is_empty() || self.len() <= i { + pub fn remove(&mut self, index: usize) -> Option { + if self.is_empty() || self.len() <= index { return None; } @@ -1173,14 +1164,14 @@ impl VecDeque { // R - Indicates element that is being removed // M - Indicates element was moved - let idx = self.wrap_add(self.tail, i); + let idx = self.wrap_add(self.tail, index); let elem = unsafe { Some(self.buffer_read(idx)) }; - let distance_to_tail = i; - let distance_to_head = self.len() - i; + let distance_to_tail = index; + let distance_to_head = self.len() - index; let contiguous = self.is_contiguous(); @@ -1195,7 +1186,7 @@ impl VecDeque { // [. . . . o o o o o o . . . . . .] // M M - self.copy(self.tail + 1, self.tail, i); + self.copy(self.tail + 1, self.tail, index); self.tail += 1; }, (true, false, _) => unsafe { @@ -1221,7 +1212,7 @@ impl VecDeque { // [o o o o o o . . . . . . o o o o] // M M - self.copy(self.tail + 1, self.tail, i); + self.copy(self.tail + 1, self.tail, index); self.tail = self.wrap_add(self.tail, 1); }, (false, false, false) => unsafe { @@ -1257,12 +1248,12 @@ impl VecDeque { // M // draw in elements in the tail section - self.copy(idx, idx + 1, self.cap - idx - 1); + self.copy(idx, idx + 1, self.cap() - idx - 1); // Prevents underflow. if self.head != 0 { // copy first element into empty spot - self.copy(self.cap - 1, 0, 1); + self.copy(self.cap() - 1, 0, 1); // move elements in the head section backwards self.copy(0, 1, self.head - 1); @@ -1284,10 +1275,10 @@ impl VecDeque { self.copy(1, 0, idx); // copy last element into empty spot - self.copy(0, self.cap - 1, 1); + self.copy(0, self.cap() - 1, 1); // move elements from tail to end forward, excluding the last one - self.copy(self.tail + 1, self.tail, self.cap - self.tail - 1); + self.copy(self.tail + 1, self.tail, self.cap() - self.tail - 1); self.tail = self.wrap_add(self.tail, 1); } @@ -1310,7 +1301,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(split_off)] + /// #![feature(split_off)] + /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect(); @@ -1339,12 +1331,12 @@ impl VecDeque { let amount_in_first = first_len - at; ptr::copy_nonoverlapping(first_half.as_ptr().offset(at as isize), - *other.ptr, + other.ptr(), amount_in_first); // just take all of the second half. ptr::copy_nonoverlapping(second_half.as_ptr(), - other.ptr.offset(amount_in_first as isize), + other.ptr().offset(amount_in_first as isize), second_len); } else { // `at` lies in the second half, need to factor in the elements we skipped @@ -1352,7 +1344,7 @@ impl VecDeque { let offset = at - first_len; let amount_in_second = second_len - offset; ptr::copy_nonoverlapping(second_half.as_ptr().offset(offset as isize), - *other.ptr, + other.ptr(), amount_in_second); } } @@ -1373,7 +1365,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(append)] + /// #![feature(append)] + /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect(); @@ -1399,7 +1392,8 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(vec_deque_retain)] + /// #![feature(vec_deque_retain)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1428,13 +1422,14 @@ impl VecDeque { } impl VecDeque { - /// Modifies the ringbuf in-place so that `len()` is equal to new_len, + /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len, /// either by removing excess elements or by appending copies of a value to the back. /// /// # Examples /// /// ``` - /// # #![feature(deque_extras)] + /// #![feature(deque_extras)] + /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1719,16 +1714,16 @@ impl Index for VecDeque { type Output = A; #[inline] - fn index(&self, i: usize) -> &A { - self.get(i).expect("Out of bounds access") + fn index(&self, index: usize) -> &A { + self.get(index).expect("Out of bounds access") } } #[stable(feature = "rust1", since = "1.0.0")] impl IndexMut for VecDeque { #[inline] - fn index_mut(&mut self, i: usize) -> &mut A { - self.get_mut(i).expect("Out of bounds access") + fn index_mut(&mut self, index: usize) -> &mut A { + self.get_mut(index).expect("Out of bounds access") } } @@ -1900,8 +1895,8 @@ mod tests { assert_eq!(tester.swap_front_remove(idx), Some(len * 2 - 1 - i)); } } - assert!(tester.tail < tester.cap); - assert!(tester.head < tester.cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); assert_eq!(tester, expected); } } @@ -1936,8 +1931,8 @@ mod tests { } } tester.insert(to_insert, to_insert); - assert!(tester.tail < tester.cap); - assert!(tester.head < tester.cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); assert_eq!(tester, expected); } } @@ -1973,8 +1968,8 @@ mod tests { tester.push_back(1234); } tester.remove(to_remove); - assert!(tester.tail < tester.cap); - assert!(tester.head < tester.cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); assert_eq!(tester, expected); } } @@ -2006,8 +2001,8 @@ mod tests { } tester.shrink_to_fit(); assert!(tester.capacity() <= cap); - assert!(tester.tail < tester.cap); - assert!(tester.head < tester.cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); assert_eq!(tester, expected); } } @@ -2040,10 +2035,10 @@ mod tests { tester.push_back(i); } let result = tester.split_off(at); - assert!(tester.tail < tester.cap); - assert!(tester.head < tester.cap); - assert!(result.tail < result.cap); - assert!(result.head < result.cap); + assert!(tester.tail < tester.cap()); + assert!(tester.head < tester.cap()); + assert!(result.tail < result.cap()); + assert!(result.head < result.cap()); assert_eq!(tester, expected_self); assert_eq!(result, expected_other); } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 685bb5dc4b..a2d378a0fa 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -11,9 +11,12 @@ //! A simple map based on a vector for small integer keys. Space requirements //! are O(highest integer key). +#![deprecated(reason = "VecMap moved to crates.io as vec_map", + since = "1.3.0")] +#![unstable(feature = "vecmap", reason = "deprecated")] +#![allow(deprecated)] + #![allow(missing_docs)] -#![unstable(feature = "vecmap", - reason = "may not be stabilized in the standard library")] use self::Entry::*; @@ -35,7 +38,8 @@ use vec::Vec; /// # Examples /// /// ``` -/// # #![feature(vecmap)] +/// #![feature(vecmap)] +/// /// use std::collections::VecMap; /// /// let mut months = VecMap::new(); @@ -135,7 +139,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// let mut map: VecMap<&str> = VecMap::new(); /// ``` @@ -148,7 +153,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// let mut map: VecMap<&str> = VecMap::with_capacity(10); /// ``` @@ -163,7 +169,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// let map: VecMap = VecMap::with_capacity(10); /// assert!(map.capacity() >= 10); @@ -183,7 +190,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// let mut map: VecMap<&str> = VecMap::new(); /// map.reserve_len(10); @@ -208,7 +216,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// let mut map: VecMap<&str> = VecMap::new(); /// map.reserve_len_exact(10); @@ -248,7 +257,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -277,7 +287,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -307,7 +318,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap, append)] + /// #![feature(vecmap, append)] + /// /// use std::collections::VecMap; /// /// let mut a = VecMap::new(); @@ -343,7 +355,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap, split_off)] + /// #![feature(vecmap, split_off)] + /// /// use std::collections::VecMap; /// /// let mut a = VecMap::new(); @@ -400,7 +413,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap, drain)] + /// #![feature(vecmap, drain)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -428,7 +442,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut a = VecMap::new(); @@ -446,7 +461,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut a = VecMap::new(); @@ -464,7 +480,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut a = VecMap::new(); @@ -480,7 +497,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -505,7 +523,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -524,7 +543,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -552,7 +572,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -578,7 +599,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); @@ -600,7 +622,8 @@ impl VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap, entry)] + /// #![feature(vecmap, entry)] + /// /// use std::collections::VecMap; /// /// let mut count: VecMap = VecMap::new(); @@ -778,7 +801,8 @@ impl IntoIterator for VecMap { /// # Examples /// /// ``` - /// # #![feature(vecmap)] + /// #![feature(vecmap)] + /// /// use std::collections::VecMap; /// /// let mut map = VecMap::new(); diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 20a3625fe5..d161dc7a28 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(ascii)] #![feature(append)] -#![feature(bit_vec_append_split_off)] #![feature(bitset)] #![feature(bitvec)] #![feature(box_syntax)] @@ -37,14 +37,16 @@ #![feature(rustc_private)] #![feature(slice_bytes)] #![feature(slice_chars)] -#![feature(slice_extras)] +#![feature(slice_splits)] #![feature(slice_position_elem)] #![feature(split_off)] #![feature(step_by)] #![feature(str_char)] #![feature(str_escape)] #![feature(str_match_indices)] +#![feature(str_split_at)] #![feature(str_utf16)] +#![feature(box_str)] #![feature(subslice_offset)] #![feature(test)] #![feature(unboxed_closures)] @@ -52,9 +54,10 @@ #![feature(vec_deque_retain)] #![feature(vec_from_raw_buf)] #![feature(vec_push_all)] -#![feature(vec_split_off)] #![feature(vecmap)] +#![allow(deprecated)] + #[macro_use] extern crate log; extern crate collections; diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index e1c4e05e19..65706b292c 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -119,71 +119,48 @@ fn test_first_mut() { } #[test] -fn test_tail() { +fn test_split_first() { let mut a = vec![11]; let b: &[i32] = &[]; - assert_eq!(a.tail(), b); + assert!(b.split_first().is_none()); + assert_eq!(a.split_first(), Some((&11, b))); a = vec![11, 12]; let b: &[i32] = &[12]; - assert_eq!(a.tail(), b); + assert_eq!(a.split_first(), Some((&11, b))); } #[test] -fn test_tail_mut() { +fn test_split_first_mut() { let mut a = vec![11]; let b: &mut [i32] = &mut []; - assert!(a.tail_mut() == b); + assert!(b.split_first_mut().is_none()); + assert!(a.split_first_mut() == Some((&mut 11, b))); a = vec![11, 12]; let b: &mut [_] = &mut [12]; - assert!(a.tail_mut() == b); + assert!(a.split_first_mut() == Some((&mut 11, b))); } #[test] -#[should_panic] -fn test_tail_empty() { - let a = Vec::::new(); - a.tail(); -} - -#[test] -#[should_panic] -fn test_tail_mut_empty() { - let mut a = Vec::::new(); - a.tail_mut(); -} - -#[test] -fn test_init() { +fn test_split_last() { let mut a = vec![11]; let b: &[i32] = &[]; - assert_eq!(a.init(), b); + assert!(b.split_last().is_none()); + assert_eq!(a.split_last(), Some((&11, b))); a = vec![11, 12]; let b: &[_] = &[11]; - assert_eq!(a.init(), b); + assert_eq!(a.split_last(), Some((&12, b))); } #[test] -fn test_init_mut() { +fn test_split_last_mut() { let mut a = vec![11]; let b: &mut [i32] = &mut []; - assert!(a.init_mut() == b); + assert!(b.split_last_mut().is_none()); + assert!(a.split_last_mut() == Some((&mut 11, b))); + a = vec![11, 12]; let b: &mut [_] = &mut [11]; - assert!(a.init_mut() == b); -} - -#[test] -#[should_panic] -fn test_init_empty() { - let a = Vec::::new(); - a.init(); -} - -#[test] -#[should_panic] -fn test_init_mut_empty() { - let mut a = Vec::::new(); - a.init_mut(); + assert!(a.split_last_mut() == Some((&mut 12, b))); } #[test] @@ -606,22 +583,22 @@ fn test_concat() { assert_eq!(d, [1, 2, 3]); let v: &[&[_]] = &[&[1], &[2, 3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 3]); let v: &[&[_]] = &[&[1], &[2], &[3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); } #[test] -fn test_connect() { +fn test_join() { let v: [Vec; 0] = []; - assert_eq!(v.connect(&0), []); - assert_eq!([vec![1], vec![2, 3]].connect(&0), [1, 0, 2, 3]); - assert_eq!([vec![1], vec![2], vec![3]].connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), []); + assert_eq!([vec![1], vec![2, 3]].join(&0), [1, 0, 2, 3]); + assert_eq!([vec![1], vec![2], vec![3]].join(&0), [1, 0, 2, 0, 3]); let v: [&[_]; 2] = [&[1], &[2, 3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 3]); let v: [&[_]; 3] = [&[1], &[2], &[3]]; - assert_eq!(v.connect(&0), [1, 0, 2, 0, 3]); + assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); } #[test] @@ -1293,6 +1270,59 @@ fn test_to_vec() { assert_eq!(ys, [1, 2, 3]); } +#[test] +fn test_box_slice_clone() { + let data = vec![vec![0, 1], vec![0], vec![1]]; + let data2 = data.clone().into_boxed_slice().clone().to_vec(); + + assert_eq!(data, data2); +} + +#[test] +fn test_box_slice_clone_panics() { + use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::thread::spawn; + + struct Canary { + count: Arc, + panics: bool + } + + impl Drop for Canary { + fn drop(&mut self) { + self.count.fetch_add(1, Ordering::SeqCst); + } + } + + impl Clone for Canary { + fn clone(&self) -> Self { + if self.panics { panic!() } + + Canary { + count: self.count.clone(), + panics: self.panics + } + } + } + + let drop_count = Arc::new(AtomicUsize::new(0)); + let canary = Canary { count: drop_count.clone(), panics: false }; + let panic = Canary { count: drop_count.clone(), panics: true }; + + spawn(move || { + // When xs is dropped, +5. + let xs = vec![canary.clone(), canary.clone(), canary.clone(), + panic, canary].into_boxed_slice(); + + // When panic is cloned, +3. + xs.clone(); + }).join().unwrap_err(); + + // Total = 8 + assert_eq!(drop_count.load(Ordering::SeqCst), 8); +} + mod bench { use std::iter::repeat; use std::{mem, ptr}; @@ -1318,7 +1348,7 @@ mod bench { #[bench] fn mut_iterator(b: &mut Bencher) { - let mut v: Vec<_> = repeat(0).take(100).collect(); + let mut v = vec![0; 100]; b.iter(|| { let mut i = 0; @@ -1339,11 +1369,11 @@ mod bench { } #[bench] - fn connect(b: &mut Bencher) { + fn join(b: &mut Bencher) { let xss: Vec> = (0..100).map(|i| (0..i).collect()).collect(); b.iter(|| { - xss.connect(&0) + xss.join(&0) }); } @@ -1419,7 +1449,7 @@ mod bench { #[bench] fn zero_1kb_from_elem(b: &mut Bencher) { b.iter(|| { - repeat(0u8).take(1024).collect::>() + vec![0u8; 1024] }); } @@ -1467,7 +1497,7 @@ mod bench { fn random_inserts(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v: Vec<_> = repeat((0, 0)).take(30).collect(); + let mut v = vec![(0, 0); 30]; for _ in 0..100 { let l = v.len(); v.insert(rng.gen::() % (l + 1), @@ -1479,7 +1509,7 @@ mod bench { fn random_removes(b: &mut Bencher) { let mut rng = thread_rng(); b.iter(|| { - let mut v: Vec<_> = repeat((0, 0)).take(130).collect(); + let mut v = vec![(0, 0); 130]; for _ in 0..100 { let l = v.len(); v.remove(rng.gen::() % l); diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 3f32136bc2..4cccb29b41 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -158,32 +158,32 @@ fn test_concat_for_different_lengths() { test_concat!("abc", ["", "a", "bc"]); } -macro_rules! test_connect { +macro_rules! test_join { ($expected: expr, $string: expr, $delim: expr) => { { - let s = $string.connect($delim); + let s = $string.join($delim); assert_eq!($expected, s); } } } #[test] -fn test_connect_for_different_types() { - test_connect!("a-b", ["a", "b"], "-"); +fn test_join_for_different_types() { + test_join!("a-b", ["a", "b"], "-"); let hyphen = "-".to_string(); - test_connect!("a-b", [s("a"), s("b")], &*hyphen); - test_connect!("a-b", vec!["a", "b"], &*hyphen); - test_connect!("a-b", &*vec!["a", "b"], "-"); - test_connect!("a-b", vec![s("a"), s("b")], "-"); + test_join!("a-b", [s("a"), s("b")], &*hyphen); + test_join!("a-b", vec!["a", "b"], &*hyphen); + test_join!("a-b", &*vec!["a", "b"], "-"); + test_join!("a-b", vec![s("a"), s("b")], "-"); } #[test] -fn test_connect_for_different_lengths() { +fn test_join_for_different_lengths() { let empty: &[&str] = &[]; - test_connect!("", empty, "-"); - test_connect!("a", ["a"], "-"); - test_connect!("a-b", ["a", "b"], "-"); - test_connect!("-a-bc", ["", "a", "bc"], "-"); + test_join!("", empty, "-"); + test_join!("a", ["a"], "-"); + test_join!("a-b", ["a", "b"], "-"); + test_join!("-a-bc", ["", "a", "bc"], "-"); } #[test] @@ -701,11 +701,23 @@ fn test_split_at() { assert_eq!(b, ""); } +#[test] +fn test_split_at_mut() { + use std::ascii::AsciiExt; + let mut s = "Hello World".to_string(); + { + let (a, b) = s.split_at_mut(5); + a.make_ascii_uppercase(); + b.make_ascii_lowercase(); + } + assert_eq!(s, "HELLO world"); +} + #[test] #[should_panic] fn test_split_at_boundscheck() { let s = "ศไทย中华Việt Nam"; - let (a, b) = s.split_at(1); + s.split_at(1); } #[test] @@ -1746,6 +1758,22 @@ fn to_uppercase() { assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ"); } +#[test] +fn test_into_string() { + // The only way to acquire a Box in the first place is through a String, so just + // test that we can round-trip between Box and String. + let string = String::from("Some text goes here"); + assert_eq!(string.clone().into_boxed_slice().into_string(), string); +} + +#[test] +fn test_box_slice_clone() { + let data = String::from("hello HELLO hello HELLO yes YES 5 中ä华!!!"); + let data2 = data.clone().into_boxed_slice().clone().into_string(); + + assert_eq!(data, data2); +} + mod pattern { use std::str::pattern::Pattern; use std::str::pattern::{Searcher, ReverseSearcher}; @@ -1820,6 +1848,14 @@ mod pattern { Match (4, 6), Reject(6, 7), ]); + make_test!(str_searcher_ascii_haystack_seq, "bb", "abbcbbbbd", [ + Reject(0, 1), + Match (1, 3), + Reject(3, 4), + Match (4, 6), + Match (6, 8), + Reject(8, 9), + ]); make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ Match (0, 0), Reject(0, 1), @@ -2073,12 +2109,12 @@ mod bench { } #[bench] - fn bench_connect(b: &mut Bencher) { + fn bench_join(b: &mut Bencher) { let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb"; let sep = "→"; let v = vec![s, s, s, s, s, s, s, s, s, s]; b.iter(|| { - assert_eq!(v.connect(sep).len(), s.len() * 10 + sep.len() * 9); + assert_eq!(v.join(sep).len(), s.len() * 10 + sep.len() * 9); }) } diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 257caca401..80283741cc 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -10,18 +10,9 @@ use std::borrow::{IntoCow, Cow}; use std::iter::repeat; -#[allow(deprecated)] -use std::string::as_string; use test::Bencher; -#[test] -#[allow(deprecated)] -fn test_as_string() { - let x = "foo"; - assert_eq!(x, &**as_string(x)); -} - #[test] fn test_from_str() { let owned: Option<::std::string::String> = "string".parse().ok(); @@ -374,6 +365,13 @@ fn test_extend_ref() { assert_eq!(&a, "foobar"); } +#[test] +fn test_into_boxed_slice() { + let xs = String::from("hello my name is bob"); + let ys = xs.into_boxed_slice(); + assert_eq!(&*ys, "hello my name is bob"); +} + #[bench] fn bench_with_capacity(b: &mut Bencher) { b.iter(|| { diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs index df63fbc62f..7b340dc5be 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollectionstest/vec.rs @@ -10,8 +10,6 @@ use std::iter::{FromIterator, repeat}; use std::mem::size_of; -#[allow(deprecated)] -use std::vec::as_vec; use test::Bencher; @@ -25,25 +23,6 @@ impl<'a> Drop for DropCounter<'a> { } } -#[test] -#[allow(deprecated)] -fn test_as_vec() { - let xs = [1u8, 2u8, 3u8]; - assert_eq!(&**as_vec(&xs), xs); -} - -#[test] -#[allow(deprecated)] -fn test_as_vec_dtor() { - let (mut count_x, mut count_y) = (0, 0); - { - let xs = &[DropCounter { count: &mut count_x }, DropCounter { count: &mut count_y }]; - assert_eq!(as_vec(xs).len(), 2); - } - assert_eq!(count_x, 1); - assert_eq!(count_y, 1); -} - #[test] fn test_small_vec_struct() { assert!(size_of::>() == size_of::() * 3); diff --git a/src/libcore/any.rs b/src/libcore/any.rs index f0c77ae866..e7b39c11f4 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Traits for dynamic typing of any `'static` type (through runtime reflection) -//! //! This module implements the `Any` trait, which enables dynamic typing //! of any `'static` type through runtime reflection. //! //! `Any` itself can be used to get a `TypeId`, and has more features when used //! as a trait object. As `&Any` (a borrowed trait object), it has the `is` and //! `as_ref` methods, to test if the contained value is of a given type, and to -//! get a reference to the inner value as a type. As`&mut Any`, there is also +//! get a reference to the inner value as a type. As `&mut Any`, there is also //! the `as_mut` method, for getting a mutable reference to the inner value. //! `Box` adds the `move` method, which will unwrap a `Box` from the //! object. See the extension traits (`*Ext`) for the full details. diff --git a/src/libcore/array.rs b/src/libcore/array.rs index a9b240de30..cfe22b8917 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -11,8 +11,9 @@ //! Implementations of things like `Eq` for fixed-length arrays //! up to a certain length. Eventually we should able to generalize //! to all lengths. +//! +//! *[See also the array primitive type](../primitive.array.html).* -#![doc(primitive = "array")] #![unstable(feature = "fixed_size_array", reason = "traits and impls are better expressed through generic \ integer constants")] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index 1b8ee8db5f..53952cdc90 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -72,12 +72,13 @@ use self::Ordering::*; -use marker::Sync; +use marker::{Send, Sync}; use intrinsics; use cell::UnsafeCell; use default::Default; +use fmt; /// A boolean type which can be safely shared between threads. #[stable(feature = "rust1", since = "1.0.0")] @@ -133,6 +134,7 @@ impl Default for AtomicPtr { } } +unsafe impl Send for AtomicPtr {} unsafe impl Sync for AtomicPtr {} /// Atomic memory orderings @@ -144,7 +146,7 @@ unsafe impl Sync for AtomicPtr {} /// "relaxed" atomics allow all reorderings. /// /// Rust's memory orderings are [the same as -/// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync). +/// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub enum Ordering { @@ -272,13 +274,13 @@ impl AtomicBool { unsafe { atomic_swap(self.v.get(), val, order) > 0 } } - /// Stores a value into the bool if the current value is the same as the expected value. + /// Stores a value into the `bool` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// - /// `swap` also takes an `Ordering` argument which describes the memory ordering of this - /// operation. + /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of + /// this operation. /// /// # Examples /// @@ -295,11 +297,11 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool { - let old = if old { UINT_TRUE } else { 0 }; + pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { + let current = if current { UINT_TRUE } else { 0 }; let new = if new { UINT_TRUE } else { 0 }; - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 } + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) > 0 } } /// Logical "and" with a boolean value. @@ -515,10 +517,10 @@ impl AtomicIsize { unsafe { atomic_swap(self.v.get(), val, order) } } - /// Stores a value into the isize if the current value is the same as the expected value. + /// Stores a value into the `isize` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -538,8 +540,8 @@ impl AtomicIsize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize { - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } + pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize { + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) } } /// Add an isize to the current value, returning the previous value. @@ -709,10 +711,10 @@ impl AtomicUsize { unsafe { atomic_swap(self.v.get(), val, order) } } - /// Stores a value into the usize if the current value is the same as the expected value. + /// Stores a value into the `usize` if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -732,8 +734,8 @@ impl AtomicUsize { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize { - unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } + pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize { + unsafe { atomic_compare_and_swap(self.v.get(), current, new, order) } } /// Add to the current usize, returning the previous value. @@ -910,10 +912,10 @@ impl AtomicPtr { unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } } - /// Stores a value into the pointer if the current value is the same as the expected value. + /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// The return value is always the previous value. If it is equal to `old`, then the value was - /// updated. + /// The return value is always the previous value. If it is equal to `current`, then the value + /// was updated. /// /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of /// this operation. @@ -933,9 +935,9 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T { + pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { unsafe { - atomic_compare_and_swap(self.p.get() as *mut usize, old as usize, + atomic_compare_and_swap(self.p.get() as *mut usize, current as usize, new as usize, order) as *mut T } } @@ -953,7 +955,6 @@ unsafe fn atomic_store(dst: *mut T, val: T, order:Ordering) { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { match order { Acquire => intrinsics::atomic_load_acq(dst), @@ -965,7 +966,6 @@ unsafe fn atomic_load(dst: *const T, order:Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -978,7 +978,6 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_add). #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xadd_acq(dst, val), @@ -991,7 +990,6 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { /// Returns the old value (like __sync_fetch_and_sub). #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xsub_acq(dst, val), @@ -1003,7 +1001,6 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_cxchg_acq(dst, old, new), @@ -1015,7 +1012,6 @@ unsafe fn atomic_compare_and_swap(dst: *mut T, old:T, new:T, order: Ordering) } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_and_acq(dst, val), @@ -1027,7 +1023,6 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_nand_acq(dst, val), @@ -1040,7 +1035,6 @@ unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_or_acq(dst, val), @@ -1053,7 +1047,6 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { #[inline] -#[stable(feature = "rust1", since = "1.0.0")] unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xor_acq(dst, val), @@ -1098,3 +1091,23 @@ pub fn fence(order: Ordering) { } } } + +macro_rules! impl_Debug { + ($($t:ident)*) => ($( + #[stable(feature = "atomic_debug", since = "1.3.0")] + impl fmt::Debug for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple(stringify!($t)).field(&self.load(Ordering::SeqCst)).finish() + } + } + )*); +} + +impl_Debug!{ AtomicUsize AtomicIsize AtomicBool } + +#[stable(feature = "atomic_debug", since = "1.3.0")] +impl fmt::Debug for AtomicPtr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + } +} diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 37f37654c1..c443270d5f 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -36,16 +36,16 @@ //! would otherwise be disallowed though, there are occasions when interior mutability might be //! appropriate, or even *must* be used, e.g. //! -//! * Introducing inherited mutability roots to shared types. +//! * Introducing mutability 'inside' of something immutable //! * Implementation details of logically-immutable methods. //! * Mutating implementations of `Clone`. //! -//! ## Introducing inherited mutability roots to shared types +//! ## Introducing mutability 'inside' of something immutable //! -//! Shared smart pointer types, including `Rc` and `Arc`, provide containers that can be +//! Many shared smart pointer types, including `Rc` and `Arc`, provide containers that can be //! cloned and shared between multiple parties. Because the contained values may be -//! multiply-aliased, they can only be borrowed as shared references, not mutable references. -//! Without cells it would be impossible to mutate data inside of shared boxes at all! +//! multiply-aliased, they can only be borrowed with `&`, not `&mut`. Without cells it would be +//! impossible to mutate data inside of these smart pointers at all. //! //! It's very common then to put a `RefCell` inside shared pointer types to reintroduce //! mutability: @@ -65,8 +65,8 @@ //! ``` //! //! Note that this example uses `Rc` and not `Arc`. `RefCell`s are for single-threaded -//! scenarios. Consider using `Mutex` if you need shared mutability in a multi-threaded -//! situation. +//! scenarios. Consider using `RwLock` or `Mutex` if you need shared mutability in a +//! multi-threaded situation. //! //! ## Implementation details of logically-immutable methods //! @@ -221,7 +221,8 @@ impl Cell { /// # Examples /// /// ``` - /// # #![feature(as_unsafe_cell)] + /// #![feature(as_unsafe_cell)] + /// /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -589,7 +590,8 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// # Example /// /// ``` - /// # #![feature(cell_extras)] + /// #![feature(cell_extras)] + /// /// use std::cell::{RefCell, Ref}; /// /// let c = RefCell::new((5, 'b')); diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 12aa06667a..c6d0e97a0c 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -13,7 +13,6 @@ //! For more details, see ::rustc_unicode::char (a.k.a. std::char) #![allow(non_snake_case)] -#![doc(primitive = "char")] #![stable(feature = "core_char", since = "1.2.0")] use iter::Iterator; @@ -85,10 +84,18 @@ pub fn from_u32(i: u32) -> Option { if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { None } else { - Some(unsafe { transmute(i) }) + Some(unsafe { from_u32_unchecked(i) }) } } +/// Converts a `u32` to an `char`, not checking whether it is a valid unicode +/// codepoint. +#[inline] +#[unstable(feature = "char_from_unchecked", reason = "recently added API")] +pub unsafe fn from_u32_unchecked(i: u32) -> char { + transmute(i) +} + /// Converts a number to the character representing it. /// /// # Return value @@ -116,12 +123,11 @@ pub fn from_digit(num: u32, radix: u32) -> Option { panic!("from_digit: radix is too high (maximum 36)"); } if num < radix { - unsafe { - if num < 10 { - Some(transmute('0' as u32 + num)) - } else { - Some(transmute('a' as u32 + num - 10)) - } + let num = num as u8; + if num < 10 { + Some((b'0' + num) as char) + } else { + Some((b'a' + num - 10) as char) } } else { None @@ -319,16 +325,13 @@ impl Iterator for EscapeUnicode { Some('{') } EscapeUnicodeState::Value(offset) => { - let v = match ((self.c as i32) >> (offset * 4)) & 0xf { - i @ 0 ... 9 => '0' as i32 + i, - i => 'a' as i32 + (i - 10) - }; + let c = from_digit(((self.c as u32) >> (offset * 4)) & 0xf, 16).unwrap(); if offset == 0 { self.state = EscapeUnicodeState::RightBrace; } else { self.state = EscapeUnicodeState::Value(offset - 1); } - Some(unsafe { transmute(v) }) + Some(c) } EscapeUnicodeState::RightBrace => { self.state = EscapeUnicodeState::Done; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 0269499ad5..9d151abea7 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -166,6 +166,8 @@ impl Ordering { /// /// - total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true; and /// - transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// +/// When this trait is `derive`d, it produces a lexicographic ordering. #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd { /// This method returns an `Ordering` between `self` and `other`. @@ -381,7 +383,8 @@ pub fn max(v1: T, v2: T) -> T { /// # Examples /// /// ``` -/// # #![feature(cmp_partial)] +/// #![feature(cmp_partial)] +/// /// use std::cmp; /// /// assert_eq!(Some(1), cmp::partial_min(1, 2)); @@ -391,7 +394,8 @@ pub fn max(v1: T, v2: T) -> T { /// When comparison is impossible: /// /// ``` -/// # #![feature(cmp_partial)] +/// #![feature(cmp_partial)] +/// /// use std::cmp; /// /// let result = cmp::partial_min(std::f64::NAN, 1.0); @@ -399,6 +403,7 @@ pub fn max(v1: T, v2: T) -> T { /// ``` #[inline] #[unstable(feature = "cmp_partial")] +#[deprecated(since = "1.3.0", reason = "has not proven itself worthwhile")] pub fn partial_min(v1: T, v2: T) -> Option { match v1.partial_cmp(&v2) { Some(Less) | Some(Equal) => Some(v1), @@ -414,7 +419,8 @@ pub fn partial_min(v1: T, v2: T) -> Option { /// # Examples /// /// ``` -/// # #![feature(cmp_partial)] +/// #![feature(cmp_partial)] +/// /// use std::cmp; /// /// assert_eq!(Some(2), cmp::partial_max(1, 2)); @@ -424,7 +430,8 @@ pub fn partial_min(v1: T, v2: T) -> Option { /// When comparison is impossible: /// /// ``` -/// # #![feature(cmp_partial)] +/// #![feature(cmp_partial)] +/// /// use std::cmp; /// /// let result = cmp::partial_max(std::f64::NAN, 1.0); @@ -432,6 +439,7 @@ pub fn partial_min(v1: T, v2: T) -> Option { /// ``` #[inline] #[unstable(feature = "cmp_partial")] +#[deprecated(since = "1.3.0", reason = "has not proven itself worthwhile")] pub fn partial_max(v1: T, v2: T) -> Option { match v1.partial_cmp(&v2) { Some(Equal) | Some(Less) => Some(v2), diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 32d6aa19c6..22f0215f0a 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -175,6 +175,12 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { fn is_pretty(&self) -> bool { self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0 } + + /// Returns the wrapped `Formatter`. + #[unstable(feature = "debug_builder_formatter", reason = "recently added")] + pub fn formatter(&mut self) -> &mut fmt::Formatter<'b> { + &mut self.fmt + } } struct DebugInner<'a, 'b: 'a> { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 343772c764..02b23c6c7e 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -267,11 +267,18 @@ impl<'a> Display for Arguments<'a> { } } -/// Format trait for the `:?` format. Useful for debugging, all types -/// should implement this. +/// Format trait for the `?` character. +/// +/// `Debug` should format the output in a programmer-facing, debugging context. /// /// Generally speaking, you should just `derive` a `Debug` implementation. /// +/// When used with the alternate format specifier `#?`, the output is pretty-printed. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// /// # Examples /// /// Deriving an implementation: @@ -309,10 +316,42 @@ impl<'a> Display for Arguments<'a> { /// println!("The origin is: {:?}", origin); /// ``` /// +/// This outputs: +/// +/// ```text +/// The origin is: Point { x: 0, y: 0 } +/// ``` +/// /// There are a number of `debug_*` methods on `Formatter` to help you with manual /// implementations, such as [`debug_struct`][debug_struct]. /// +/// `Debug` implementations using either `derive` or the debug builder API +/// on `Formatter` support pretty printing using the alternate flag: `{:#?}`. +/// /// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct +/// +/// Pretty printing with `#?`: +/// +/// ``` +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {:#?}", origin); +/// ``` +/// +/// This outputs: +/// +/// ```text +/// The origin is: Point { +/// x: 0, +/// y: 0 +/// } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \ defined in your crate, add `#[derive(Debug)]` or \ @@ -324,8 +363,39 @@ pub trait Debug { fn fmt(&self, &mut Formatter) -> Result; } -/// When a value can be semantically expressed as a String, this trait may be -/// used. It corresponds to the default format, `{}`. +/// Format trait for an empty format, `{}`. +/// +/// `Display` is similar to [`Debug`][debug], but `Display` is for user-facing +/// output, and so cannot be derived. +/// +/// [debug]: trait.Debug.html +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Implementing `Display` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl fmt::Display for Point { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {})", self.x, self.y) +/// } +/// } +/// +/// let origin = Point { x: 0, y: 0 }; +/// +/// println!("The origin is: {}", origin); +/// ``` #[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \ formatter; try using `:?` instead if you are using \ a format string"] @@ -336,7 +406,46 @@ pub trait Display { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `o` character +/// Format trait for the `o` character. +/// +/// The `Octal` trait should format its output as a number in base-8. +/// +/// The alternate flag, `#`, adds a `0o` in front of the output. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `i32`: +/// +/// ``` +/// let x = 42; // 42 is '52' in octal +/// +/// assert_eq!(format!("{:o}", x), "52"); +/// assert_eq!(format!("{:#o}", x), "0o52"); +/// ``` +/// +/// Implementing `Octal` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::Octal for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// +/// write!(f, "{:o}", val) // delegate to i32's implementation +/// } +/// } +/// +/// let l = Length(9); +/// +/// println!("l as octal is: {:o}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Octal { /// Formats the value using the given formatter. @@ -344,7 +453,46 @@ pub trait Octal { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `b` character +/// Format trait for the `b` character. +/// +/// The `Binary` trait should format its output as a number in binary. +/// +/// The alternate flag, `#`, adds a `0b` in front of the output. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `i32`: +/// +/// ``` +/// let x = 42; // 42 is '101010' in binary +/// +/// assert_eq!(format!("{:b}", x), "101010"); +/// assert_eq!(format!("{:#b}", x), "0b101010"); +/// ``` +/// +/// Implementing `Binary` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::Binary for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// +/// write!(f, "{:b}", val) // delegate to i32's implementation +/// } +/// } +/// +/// let l = Length(107); +/// +/// println!("l as binary is: {:b}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Binary { /// Formats the value using the given formatter. @@ -352,7 +500,47 @@ pub trait Binary { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `x` character +/// Format trait for the `x` character. +/// +/// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f` +/// in lower case. +/// +/// The alternate flag, `#`, adds a `0x` in front of the output. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `i32`: +/// +/// ``` +/// let x = 42; // 42 is '2a' in hex +/// +/// assert_eq!(format!("{:x}", x), "2a"); +/// assert_eq!(format!("{:#x}", x), "0x2a"); +/// ``` +/// +/// Implementing `LowerHex` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::LowerHex for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// +/// write!(f, "{:x}", val) // delegate to i32's implementation +/// } +/// } +/// +/// let l = Length(9); +/// +/// println!("l as hex is: {:x}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait LowerHex { /// Formats the value using the given formatter. @@ -360,7 +548,47 @@ pub trait LowerHex { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `X` character +/// Format trait for the `X` character. +/// +/// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F` +/// in upper case. +/// +/// The alternate flag, `#`, adds a `0x` in front of the output. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `i32`: +/// +/// ``` +/// let x = 42; // 42 is '2A' in hex +/// +/// assert_eq!(format!("{:X}", x), "2A"); +/// assert_eq!(format!("{:#X}", x), "0x2A"); +/// ``` +/// +/// Implementing `UpperHex` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::UpperHex for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// +/// write!(f, "{:X}", val) // delegate to i32's implementation +/// } +/// } +/// +/// let l = Length(9); +/// +/// println!("l as hex is: {:X}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait UpperHex { /// Formats the value using the given formatter. @@ -368,7 +596,44 @@ pub trait UpperHex { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `p` character +/// Format trait for the `p` character. +/// +/// The `Pointer` trait should format its output as a memory location. This is commonly presented +/// as hexidecimal. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `&i32`: +/// +/// ``` +/// let x = &42; +/// +/// let address = format!("{:p}", x); // this produces something like '0x7f06092ac6d0' +/// ``` +/// +/// Implementing `Pointer` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::Pointer for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// // use `as` to convert to a `*const T`, which implements Pointer, which we can use +/// +/// write!(f, "{:p}", self as *const Length) +/// } +/// } +/// +/// let l = Length(42); +/// +/// println!("l is in memory here: {:p}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Pointer { /// Formats the value using the given formatter. @@ -376,7 +641,42 @@ pub trait Pointer { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `e` character +/// Format trait for the `e` character. +/// +/// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `i32`: +/// +/// ``` +/// let x = 42.0; // 42.0 is '4.2e1' in scientific notation +/// +/// assert_eq!(format!("{:e}", x), "4.2e1"); +/// ``` +/// +/// Implementing `LowerExp` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::LowerExp for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// write!(f, "{}e1", val / 10) +/// } +/// } +/// +/// let l = Length(100); +/// +/// println!("l in scientific notation is: {:e}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait LowerExp { /// Formats the value using the given formatter. @@ -384,7 +684,42 @@ pub trait LowerExp { fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `E` character +/// Format trait for the `E` character. +/// +/// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`. +/// +/// For more information on formatters, see [the module-level documentation][module]. +/// +/// [module]: ../index.html +/// +/// # Examples +/// +/// Basic usage with `f32`: +/// +/// ``` +/// let x = 42.0; // 42.0 is '4.2E1' in scientific notation +/// +/// assert_eq!(format!("{:E}", x), "4.2E1"); +/// ``` +/// +/// Implementing `UpperExp` on a type: +/// +/// ``` +/// use std::fmt; +/// +/// struct Length(i32); +/// +/// impl fmt::UpperExp for Length { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// let val = self.0; +/// write!(f, "{}E1", val / 10) +/// } +/// } +/// +/// let l = Length(100); +/// +/// println!("l in scientific notation is: {:E}", l); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait UpperExp { /// Formats the value using the given formatter. @@ -952,7 +1287,7 @@ impl Debug for str { fn fmt(&self, f: &mut Formatter) -> Result { try!(write!(f, "\"")); for c in self.chars().flat_map(|c| c.escape_default()) { - try!(write!(f, "{}", c)); + try!(f.write_char(c)) } write!(f, "\"") } @@ -971,7 +1306,7 @@ impl Debug for char { use char::CharExt; try!(write!(f, "'")); for c in self.escape_default() { - try!(write!(f, "{}", c)); + try!(f.write_char(c)) } write!(f, "'") } @@ -1153,20 +1488,19 @@ macro_rules! tuple { impl<$($name:Debug),*> Debug for ($($name,)*) { #[allow(non_snake_case, unused_assignments)] fn fmt(&self, f: &mut Formatter) -> Result { - try!(write!(f, "(")); + let mut builder = f.debug_tuple(""); let ($(ref $name,)*) = *self; let mut n = 0; $( - if n > 0 { - try!(write!(f, ", ")); - } - try!(write!(f, "{:?}", *$name)); + builder.field($name); n += 1; )* + if n == 1 { - try!(write!(f, ",")); + try!(write!(builder.formatter(), ",")); } - write!(f, ")") + + builder.finish() } } peel! { $($name,)* } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index fc49f87d10..7cacc6af57 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -12,26 +12,31 @@ // FIXME: #6220 Implement floating point formatting -#![allow(unsigned_negation)] - use prelude::*; use fmt; use num::Zero; use ops::{Div, Rem, Sub}; use str; +use slice; +use ptr; +use mem; #[doc(hidden)] trait Int: Zero + PartialEq + PartialOrd + Div + Rem + Sub + Copy { fn from_u8(u: u8) -> Self; fn to_u8(&self) -> u8; + fn to_u32(&self) -> u32; + fn to_u64(&self) -> u64; } macro_rules! doit { ($($t:ident)*) => ($(impl Int for $t { fn from_u8(u: u8) -> $t { u as $t } fn to_u8(&self) -> u8 { *self as u8 } + fn to_u32(&self) -> u32 { *self as u32 } + fn to_u64(&self) -> u64 { *self as u64 } })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } @@ -162,7 +167,8 @@ pub struct RadixFmt(T, R); /// # Examples /// /// ``` -/// # #![feature(fmt_radix)] +/// #![feature(fmt_radix)] +/// /// use std::fmt::radix; /// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string()); /// ``` @@ -188,6 +194,7 @@ macro_rules! radix_fmt { } } } + macro_rules! int_base { ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { #[stable(feature = "rust1", since = "1.0.0")] @@ -209,9 +216,9 @@ macro_rules! debug { } } } + macro_rules! integer { ($Int:ident, $Uint:ident) => { - int_base! { Display for $Int as $Int -> Decimal } int_base! { Binary for $Int as $Uint -> Binary } int_base! { Octal for $Int as $Uint -> Octal } int_base! { LowerHex for $Int as $Uint -> LowerHex } @@ -219,7 +226,6 @@ macro_rules! integer { radix_fmt! { $Int as $Int, fmt_int } debug! { $Int } - int_base! { Display for $Uint as $Uint -> Decimal } int_base! { Binary for $Uint as $Uint -> Binary } int_base! { Octal for $Uint as $Uint -> Octal } int_base! { LowerHex for $Uint as $Uint -> LowerHex } @@ -233,3 +239,80 @@ integer! { i8, u8 } integer! { i16, u16 } integer! { i32, u32 } integer! { i64, u64 } + +const DEC_DIGITS_LUT: &'static[u8] = + b"0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +macro_rules! impl_Display { + ($($t:ident),*: $conv_fn:ident) => ($( + impl fmt::Display for $t { + #[allow(unused_comparisons)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let is_positive = *self >= 0; + let mut n = if is_positive { + self.$conv_fn() + } else { + // convert the negative num to positive by summing 1 to it's 2 complement + (!self.$conv_fn()).wrapping_add(1) + }; + let mut buf: [u8; 20] = unsafe { mem::uninitialized() }; + let mut curr = buf.len() as isize; + let buf_ptr = buf.as_mut_ptr(); + let lut_ptr = DEC_DIGITS_LUT.as_ptr(); + + unsafe { + // eagerly decode 4 characters at a time + if <$t>::max_value() as u64 >= 10000 { + while n >= 10000 { + let rem = (n % 10000) as isize; + n /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + } + } + + // if we reach here numbers are <= 9999, so at most 4 chars long + let mut n = n as isize; // possibly reduce 64bit math + + // decode 2 more chars, if > 2 chars + if n >= 100 { + let d1 = (n % 100) << 1; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + + // decode last 1 or 2 chars + if n < 10 { + curr -= 1; + *buf_ptr.offset(curr) = (n as u8) + 48; + } else { + let d1 = n << 1; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + } + } + + let buf_slice = unsafe { + str::from_utf8_unchecked( + slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize)) + }; + f.pad_integral(is_positive, "", buf_slice) + } + })*); +} + +impl_Display!(i8, u8, i16, u16, i32, u32: to_u32); +impl_Display!(i64, u64: to_u64); +#[cfg(target_pointer_width = "32")] +impl_Display!(isize, usize: to_u32); +#[cfg(target_pointer_width = "64")] +impl_Display!(isize, usize: to_u64); diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index abf9e55a1f..e35f380d06 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -16,7 +16,8 @@ //! # Examples //! //! ```rust -//! # #![feature(hash_default)] +//! #![feature(hash_default)] +//! //! use std::hash::{hash, Hash, SipHasher}; //! //! #[derive(Hash)] @@ -36,7 +37,8 @@ //! the trait `Hash`: //! //! ```rust -//! # #![feature(hash_default)] +//! #![feature(hash_default)] +//! //! use std::hash::{hash, Hash, Hasher, SipHasher}; //! //! struct Person { @@ -89,8 +91,7 @@ pub trait Hash { fn hash(&self, state: &mut H); /// Feeds a slice of this type into the state provided. - #[unstable(feature = "hash_slice", - reason = "module was recently redesigned")] + #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where Self: Sized { for piece in data { piece.hash(state); @@ -111,29 +112,29 @@ pub trait Hasher { /// Write a single `u8` into this hasher #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u8(&mut self, i: u8) { self.write(&[i]) } /// Write a single `u16` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u16(&mut self, i: u16) { self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) }) } /// Write a single `u32` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u32(&mut self, i: u32) { self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) }) } /// Write a single `u64` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } /// Write a single `usize` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_usize(&mut self, i: usize) { if cfg!(target_pointer_width = "32") { self.write_u32(i as u32) @@ -144,23 +145,23 @@ pub trait Hasher { /// Write a single `i8` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) } /// Write a single `i16` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) } /// Write a single `i32` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) } /// Write a single `i64` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } /// Write a single `isize` into this hasher. #[inline] - #[unstable(feature = "hasher_write", reason = "module was recently redesigned")] + #[stable(feature = "hasher_write", since = "1.3.0")] fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) } } @@ -171,6 +172,8 @@ pub trait Hasher { #[unstable(feature = "hash_default", reason = "not the most ergonomic interface unless `H` is defaulted \ to SipHasher, but perhaps not ready to commit to that")] +#[deprecated(since = "1.3.0", + reason = "has yet to prove itself useful")] pub fn hash(value: &T) -> u64 { let mut h: H = Default::default(); value.hash(&mut h); diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index a92b72e0f0..93bdadff54 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -10,8 +10,7 @@ //! An implementation of SipHash 2-4. -#![allow(deprecated)] // until the next snapshot for inherent wrapping ops - +use ptr; use prelude::*; use super::Hasher; @@ -33,9 +32,13 @@ pub struct SipHasher { k0: u64, k1: u64, length: usize, // how many bytes we've processed + // v0, v2 and v1, v3 show up in pairs in the algorithm, + // and simd implementations of SipHash will use vectors + // of v02 and v13. By placing them in this order in the struct, + // the compiler can pick up on just a few simd optimizations by itself. v0: u64, // hash state - v1: u64, v2: u64, + v1: u64, v3: u64, tail: u64, // unprocessed bytes le ntail: usize, // how many bytes in tail are valid @@ -67,6 +70,20 @@ macro_rules! u8to64_le { }); } +/// Load a full u64 word from a byte stream, in LE order. Use +/// `copy_nonoverlapping` to let the compiler generate the most efficient way +/// to load u64 from a possibly unaligned address. +/// +/// Unsafe because: unchecked indexing at i..i+8 +#[inline] +unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 { + debug_assert!(i + 8 <= buf.len()); + let mut data = 0u64; + ptr::copy_nonoverlapping(buf.get_unchecked(i), + &mut data as *mut _ as *mut u8, 8); + data.to_le() +} + macro_rules! rotl { ($x:expr, $b:expr) => (($x << $b) | ($x >> (64_i32.wrapping_sub($b)))) @@ -148,12 +165,11 @@ impl SipHasher { // Buffered tail is now flushed, process new input. let len = length - needed; - let end = len & (!0x7); let left = len & 0x7; let mut i = needed; - while i < end { - let mi = u8to64_le!(msg, i); + while i < len - left { + let mi = unsafe { load_u64_le(msg, i) }; self.v3 ^= mi; compress!(self.v0, self.v1, self.v2, self.v3); diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 455928077d..80b7587ed3 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -187,7 +187,7 @@ extern "rust-intrinsic" { /// Moves a value to an uninitialized memory location. /// /// Drop glue is not run on the destination. - pub fn move_val_init(dst: &mut T, src: T); + pub fn move_val_init(dst: *mut T, src: T); pub fn min_align_of() -> usize; pub fn pref_align_of() -> usize; @@ -586,20 +586,25 @@ extern "rust-intrinsic" { pub fn overflowing_mul(a: T, b: T) -> T; /// Performs an unchecked signed division, which results in undefined behavior, - /// in cases where y == 0, or x == int::MIN and y == -1 + /// in cases where y == 0, or x == isize::MIN and y == -1 pub fn unchecked_sdiv(x: T, y: T) -> T; /// Performs an unchecked unsigned division, which results in undefined behavior, /// in cases where y == 0 pub fn unchecked_udiv(x: T, y: T) -> T; /// Returns the remainder of an unchecked signed division, which results in - /// undefined behavior, in cases where y == 0, or x == int::MIN and y == -1 - pub fn unchecked_urem(x: T, y: T) -> T; - /// Returns the remainder of an unchecked signed division, which results in - /// undefined behavior, in cases where y == 0 + /// undefined behavior, in cases where y == 0, or x == isize::MIN and y == -1 pub fn unchecked_srem(x: T, y: T) -> T; + /// Returns the remainder of an unchecked unsigned division, which results in + /// undefined behavior, in cases where y == 0 + pub fn unchecked_urem(x: T, y: T) -> T; /// Returns the value of the discriminant for the variant in 'v', /// cast to a `u64`; if `T` has no discriminant, returns 0. pub fn discriminant_value(v: &T) -> u64; + + /// Rust's "try catch" construct which invokes the function pointer `f` with + /// the data pointer `data`, returning the exception payload if an exception + /// is thrown (aka the thread panics). + pub fn try(f: fn(*mut u8), data: *mut u8) -> *mut u8; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3026f91e85..2968d63454 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -56,6 +56,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] use self::MinMaxResult::*; use clone::Clone; @@ -445,6 +446,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[allow(deprecated)] fn scan(self, initial_state: St, f: F) -> Scan where Self: Sized, F: FnMut(&mut St, Self::Item) -> Option, { @@ -822,7 +824,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(iter_min_max)] + /// #![feature(iter_min_max)] + /// /// use std::iter::MinMaxResult::{NoElements, OneElement, MinMax}; /// /// let a: [i32; 0] = []; @@ -840,6 +843,8 @@ pub trait Iterator { #[unstable(feature = "iter_min_max", reason = "return type may change or may wish to have a closure \ based version as well")] + #[deprecated(since = "1.3.0", reason = "has not proven itself")] + #[allow(deprecated)] fn min_max(mut self) -> MinMaxResult where Self: Sized, Self::Item: Ord { let (mut min, mut max) = match self.next() { @@ -894,7 +899,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(iter_cmp)] + /// #![feature(iter_cmp)] + /// /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().max_by(|x| x.abs()).unwrap(), -10); /// ``` @@ -922,7 +928,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(iter_cmp)] + /// #![feature(iter_cmp)] + /// /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().min_by(|x| x.abs()).unwrap(), 0); /// ``` @@ -1061,7 +1068,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(iter_arith)] + /// #![feature(iter_arith)] + /// /// let a = [1, 2, 3, 4, 5]; /// let it = a.iter(); /// assert_eq!(it.sum::(), 15); @@ -1079,7 +1087,8 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(iter_arith)] + /// #![feature(iter_arith)] + /// /// fn factorial(n: u32) -> u32 { /// (1..).take_while(|&i| i <= n).product() /// } @@ -1336,6 +1345,8 @@ impl RandomAccessIterator for Rev #[derive(Clone, PartialEq, Debug)] #[unstable(feature = "iter_min_max", reason = "unclear whether such a fine-grained result is widely useful")] +#[deprecated(since = "1.3.0", reason = "has not proven itself")] +#[allow(deprecated)] pub enum MinMaxResult { /// Empty iterator NoElements, @@ -1349,6 +1360,8 @@ pub enum MinMaxResult { } #[unstable(feature = "iter_min_max", reason = "type is unstable")] +#[deprecated(since = "1.3.0", reason = "has not proven itself")] +#[allow(deprecated)] impl MinMaxResult { /// `into_option` creates an `Option` of type `(T,T)`. The returned `Option` /// has variant `None` if and only if the `MinMaxResult` has variant @@ -1359,7 +1372,8 @@ impl MinMaxResult { /// # Examples /// /// ``` - /// # #![feature(iter_min_max)] + /// #![feature(iter_min_max)] + /// /// use std::iter::MinMaxResult::{self, NoElements, OneElement, MinMax}; /// /// let r: MinMaxResult = NoElements; @@ -2249,6 +2263,7 @@ impl ExactSizeIterator for Take where I: ExactSizeIterator {} #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] +#[allow(deprecated)] pub struct Scan { iter: I, f: F, @@ -2256,6 +2271,7 @@ pub struct Scan { /// The current internal state to be passed to the closure next. #[unstable(feature = "scan_state", reason = "public fields are otherwise rare in the stdlib")] + #[deprecated(since = "1.3.0", reason = "unclear whether this is necessary")] pub state: St, } @@ -2267,6 +2283,7 @@ impl Iterator for Scan where type Item = B; #[inline] + #[allow(deprecated)] fn next(&mut self) -> Option { self.iter.next().and_then(|a| (self.f)(&mut self.state, a)) } @@ -2448,6 +2465,8 @@ impl Fuse { /// previously returned `None`. #[inline] #[unstable(feature = "iter_reset_fuse", reason = "seems marginal")] + #[deprecated(since = "1.3.0", + reason = "unusual for adaptors to have one-off methods")] pub fn reset_fuse(&mut self) { self.done = false } @@ -2555,7 +2574,7 @@ impl RandomAccessIterator for Inspect #[unstable(feature = "iter_unfold")] #[derive(Clone)] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub struct Unfold { @@ -2567,7 +2586,7 @@ pub struct Unfold { #[unstable(feature = "iter_unfold")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] impl Unfold where F: FnMut(&mut St) -> Option { @@ -2655,8 +2674,8 @@ macro_rules! step_impl_signed { #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t, by: &$t) -> Option { if *by == 0 { return None; } - let mut diff: usize; - let mut by_u: usize; + let diff: usize; + let by_u: usize; if *by > 0 { if *start >= *end { return Some(0); @@ -2751,7 +2770,8 @@ impl ops::Range { /// # Examples /// /// ``` - /// # #![feature(step_by)] + /// #![feature(step_by)] + /// /// for i in (0..10).step_by(2) { /// println!("{}", i); /// } @@ -3018,7 +3038,7 @@ type IterateState = (F, Option, bool); /// from a given seed value. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub type Iterate = Unfold, fn(&mut IterateState) -> Option>; @@ -3027,7 +3047,7 @@ pub type Iterate = Unfold, fn(&mut IterateState) /// repeated applications of the given function `f`. #[unstable(feature = "iter_iterate")] #[deprecated(since = "1.2.0", - reason = "has gained enough traction to retain its position \ + reason = "has not gained enough traction to retain its position \ in the standard library")] #[allow(deprecated)] pub fn iterate(seed: T, f: F) -> Iterate where diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 392eaf7801..238644c4a2 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -155,28 +155,26 @@ pub mod str; pub mod hash; pub mod fmt; -#[doc(primitive = "bool")] -mod bool { -} - // note: does not need to be public mod tuple; +// A curious inner-module that's not exported that contains the bindings of core +// so that compiler-expanded references to `core::$foo` can be resolved within +// core itself. +// +// Note that no crate-defined macros require this module due to the existence of +// the `$crate` meta variable, only those expansions defined in the compiler +// require this. This is because the compiler doesn't currently know that it's +// compiling the core library when it's compiling this library, so it expands +// all references to `::core::$foo` #[doc(hidden)] mod core { - pub use intrinsics; - pub use panicking; - pub use fmt; - pub use clone; - pub use cmp; - pub use hash; - pub use marker; - pub use option; - pub use iter; -} - -#[doc(hidden)] -mod std { - // range syntax - pub use ops; + pub use intrinsics; // derive(PartialOrd) + pub use fmt; // format_args! + pub use clone; // derive(Clone) + pub use cmp; // derive(Ord) + pub use hash; // derive(Hash) + pub use marker; // derive(Copy) + pub use option; // iterator protocol + pub use iter; // iterator protocol } diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 14bb82dff7..9f4d61a50d 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -17,7 +17,7 @@ macro_rules! panic { ); ($msg:expr) => ({ static _MSG_FILE_LINE: (&'static str, &'static str, u32) = ($msg, file!(), line!()); - ::core::panicking::panic(&_MSG_FILE_LINE) + $crate::panicking::panic(&_MSG_FILE_LINE) }); ($fmt:expr, $($arg:tt)*) => ({ // The leading _'s are to avoid dead code warnings if this is @@ -25,7 +25,7 @@ macro_rules! panic { // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - ::core::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE) + $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE) }); } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index dd60164a11..ebd6ba544e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -205,7 +205,7 @@ pub trait Copy : Clone { /// 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 behaviour (for example, -/// `transmute`-ing from `&T` to `&mut T` is illegal). +/// `transmute`-ing from `&T` to `&mut T` is invalid). #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index b53b61e517..7e63c8d71f 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -253,20 +253,84 @@ pub unsafe fn dropped() -> T { dropped_impl() } -/// Creates an uninitialized value. +/// Bypasses Rust's normal memory-initialization checks by pretending to +/// produce a value of type T, while doing nothing at all. /// -/// 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 uninitialized data, likely leading to crashes. +/// **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 sometimes, but should generally be avoided. +/// This is useful for FFI functions and initializing arrays sometimes, +/// but should generally be avoided. +/// +/// # Undefined Behaviour +/// +/// It is Undefined Behaviour 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. +/// +/// 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. +/// +/// If this value *does* need some kind of 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. /// /// # Examples /// +/// Here's how to safely initialize an array of `Vec`s. +/// /// ``` /// use std::mem; +/// use std::ptr; /// -/// let x: i32 = unsafe { mem::uninitialized() }; +/// // Only declare the array. This safely leaves it +/// // uninitialized in a way that Rust will track for us. +/// // However we can't initialize it element-by-element +/// // safely, and we can't use the `[value; 1000]` +/// // constructor because it only works with `Copy` data. +/// let mut data: [Vec; 1000]; +/// +/// unsafe { +/// // So we need to do this to initialize it. +/// data = mem::uninitialized(); +/// +/// // DANGER ZONE: if anything panics or otherwise +/// // incorrectly reads the array here, we will have +/// // Undefined Behaviour. +/// +/// // It's ok to mutably iterate the data, since this +/// // doesn't involve reading it at all. +/// // (ptr and len are statically known for arrays) +/// for elem in &mut data[..] { +/// // *elem = Vec::new() would try to drop the +/// // uninitialized memory at `elem` -- bad! +/// // +/// // Vec::new doesn't allocate or do really +/// // anything. It's only safe to call here +/// // because we know it won't panic. +/// ptr::write(elem, Vec::new()); +/// } +/// +/// // SAFE ZONE: everything is initialized. +/// } +/// +/// 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 +/// 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: +/// +/// ``` +/// let data: Vec> = vec![Vec::new(); 1000]; +/// println!("{:?}", &data[0]); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -365,11 +429,48 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// This function can be used to destroy any value by allowing `drop` to take ownership of its -/// argument. +/// While this does call the argument's implementation of `Drop`, it will not +/// release any borrows, as borrows are based on lexical scope. /// /// # Examples /// +/// Basic usage: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// +/// drop(v); // explicitly drop the vector +/// ``` +/// +/// Borrows are based on lexical scope, so this produces an error: +/// +/// ```ignore +/// let mut v = vec![1, 2, 3]; +/// let x = &v[0]; +/// +/// drop(x); // explicitly drop the reference, but the borrow still exists +/// +/// v.push(4); // error: cannot borrow `v` as mutable because it is also +/// // borrowed as immutable +/// ``` +/// +/// An inner scope is needed to fix this: +/// +/// ``` +/// let mut v = vec![1, 2, 3]; +/// +/// { +/// let x = &v[0]; +/// +/// drop(x); // this is now redundant, as `x` is going out of scope anyway +/// } +/// +/// v.push(4); // no problems +/// ``` +/// +/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can +/// seemingly release a borrow of one: +/// /// ``` /// use std::cell::RefCell; /// @@ -408,17 +509,22 @@ macro_rules! repeat_u8_as_u64 { // // And of course, 0x00 brings back the old world of zero'ing on drop. #[unstable(feature = "filling_drop")] +#[allow(missing_docs)] pub const POST_DROP_U8: u8 = 0x1d; #[unstable(feature = "filling_drop")] +#[allow(missing_docs)] pub const POST_DROP_U32: u32 = repeat_u8_as_u32!(POST_DROP_U8); #[unstable(feature = "filling_drop")] +#[allow(missing_docs)] pub const POST_DROP_U64: u64 = repeat_u8_as_u64!(POST_DROP_U8); #[cfg(target_pointer_width = "32")] #[unstable(feature = "filling_drop")] +#[allow(missing_docs)] pub const POST_DROP_USIZE: usize = POST_DROP_U32 as usize; #[cfg(target_pointer_width = "64")] #[unstable(feature = "filling_drop")] +#[allow(missing_docs)] pub const POST_DROP_USIZE: usize = POST_DROP_U64 as usize; /// Interprets `src` as `&U`, and then reads `src` without moving the contained diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index aade906165..6b4424093b 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,7 +10,6 @@ //! Operations and constants for 32-bits floats (`f32` type) -#![doc(primitive = "f32")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] @@ -24,14 +23,18 @@ use num::{Float, ParseFloatError}; use num::FpCategory as Fp; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const RADIX: u32 = 2; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MANTISSA_DIGITS: u32 = 24; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const DIGITS: u32 = 6; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const EPSILON: f32 = 1.19209290e-07_f32; /// Smallest finite f32 value @@ -45,20 +48,27 @@ pub const MIN_POSITIVE: f32 = 1.17549435e-38_f32; pub const MAX: f32 = 3.40282347e+38_f32; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN_EXP: i32 = -125; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX_EXP: i32 = 128; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN_10_EXP: i32 = -37; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX_10_EXP: i32 = 38; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const NAN: f32 = 0.0_f32/0.0_f32; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const INFINITY: f32 = 1.0_f32/0.0_f32; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32; /// Basic mathematial constants. @@ -215,13 +225,37 @@ impl Float for f32 { /// Rounds towards minus infinity. #[inline] fn floor(self) -> f32 { - unsafe { intrinsics::floorf32(self) } + return floorf(self); + + // On MSVC LLVM will lower many math intrinsics to a call to the + // corresponding function. On MSVC, however, many of these functions + // aren't actually available as symbols to call, but rather they are all + // `static inline` functions in header files. This means that from a C + // perspective it's "compatible", but not so much from an ABI + // perspective (which we're worried about). + // + // The inline header functions always just cast to a f64 and do their + // operation, so we do that here as well, but only for MSVC targets. + // + // Note that there are many MSVC-specific float operations which + // redirect to this comment, so `floorf` is just one case of a missing + // function on MSVC, but there are many others elsewhere. + #[cfg(target_env = "msvc")] + fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 } + #[cfg(not(target_env = "msvc"))] + fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } } } /// Rounds towards plus infinity. #[inline] fn ceil(self) -> f32 { - unsafe { intrinsics::ceilf32(self) } + return ceilf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 } + #[cfg(not(target_env = "msvc"))] + fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } } } /// Rounds to nearest integer. Rounds half-way cases away from zero. @@ -299,7 +333,13 @@ impl Float for f32 { #[inline] fn powf(self, n: f32) -> f32 { - unsafe { intrinsics::powf32(self, n) } + return powf(self, n); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 } + #[cfg(not(target_env = "msvc"))] + fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } } } #[inline] @@ -317,7 +357,13 @@ impl Float for f32 { /// Returns the exponential of the number. #[inline] fn exp(self) -> f32 { - unsafe { intrinsics::expf32(self) } + return expf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn expf(f: f32) -> f32 { (f as f64).exp() as f32 } + #[cfg(not(target_env = "msvc"))] + fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } } } /// Returns 2 raised to the power of the number. @@ -329,7 +375,13 @@ impl Float for f32 { /// Returns the natural logarithm of the number. #[inline] fn ln(self) -> f32 { - unsafe { intrinsics::logf32(self) } + return logf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn logf(f: f32) -> f32 { (f as f64).ln() as f32 } + #[cfg(not(target_env = "msvc"))] + fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } } } /// Returns the logarithm of the number with respect to an arbitrary base. @@ -345,7 +397,13 @@ impl Float for f32 { /// Returns the base 10 logarithm of the number. #[inline] fn log10(self) -> f32 { - unsafe { intrinsics::log10f32(self) } + return log10f(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 } + #[cfg(not(target_env = "msvc"))] + fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } } } /// Converts to degrees, assuming the number is in radians. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 7c9e846af9..fa7aa2ab5c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,7 +10,6 @@ //! Operations and constants for 64-bits floats (`f64` type) -#![doc(primitive = "f64")] // FIXME: MIN_VALUE and MAX_VALUE literals are parsed as -inf and inf #14353 #![allow(overflowing_literals)] @@ -24,14 +23,18 @@ use num::FpCategory as Fp; use num::{Float, ParseFloatError}; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const RADIX: u32 = 2; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MANTISSA_DIGITS: u32 = 53; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const DIGITS: u32 = 15; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; /// Smallest finite f64 value @@ -45,20 +48,27 @@ pub const MIN_POSITIVE: f64 = 2.2250738585072014e-308_f64; pub const MAX: f64 = 1.7976931348623157e+308_f64; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN_EXP: i32 = -1021; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX_EXP: i32 = 1024; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN_10_EXP: i32 = -307; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX_10_EXP: i32 = 308; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const NAN: f64 = 0.0_f64/0.0_f64; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const INFINITY: f64 = 1.0_f64/0.0_f64; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64; /// Basic mathematial constants. diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 5ea60d0d96..dacb4ebcdf 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 16-bits integers (`i16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i16")] int_module! { i16, 16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 7d9faa998c..250d66de70 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 32-bits integers (`i32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i32")] int_module! { i32, 32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 5a70911387..5ed21d7246 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 64-bits integers (`i64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i64")] int_module! { i64, 64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 1d7d78ffa6..0394c12d5c 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -11,6 +11,5 @@ //! Operations and constants for signed 8-bits integers (`i8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "i8")] int_module! { i8, 8 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index efc9123880..cb9bffca84 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -16,21 +16,25 @@ macro_rules! int_module { ($T:ty, $bits:expr) => ( // calling the `mem::size_of` function. #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BITS : usize = $bits; // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of // calling the `mem::size_of` function. #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BYTES : usize = ($bits / 8); // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of // calling the `Bounded::min_value` function. #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN: $T = (-1 as $T) << (BITS - 1); // FIXME(#9837): Compute MIN like this so the high bits that shouldn't exist are 0. // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of // calling the `Bounded::max_value` function. #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX: $T = !MIN; ) } diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 2cdfe03eaf..066cb10cce 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -11,7 +11,6 @@ //! Operations and constants for pointer-sized signed integers (`isize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "isize")] #[cfg(target_pointer_width = "32")] int_module! { isize, 32 } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 97b4f77675..ad891bf8fa 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -24,6 +24,7 @@ use mem::size_of; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; use str::{FromStr, StrExt}; +use slice::SliceExt; /// Provides intentionally-wrapped arithmetic on `T`. /// @@ -459,7 +460,7 @@ macro_rules! int_impl { } } - /// Wrapping (modular) division. Computes `floor(self / other)`, + /// Wrapping (modular) division. Computes `self / other`, /// wrapping around at the boundary of the type. /// /// The only case where such wrapping can occur is when one @@ -467,7 +468,7 @@ macro_rules! int_impl { /// negative minimal value for the type); this is equivalent /// to `-MIN`, a positive value that is too large to represent /// in the type. In such a case, this function returns `MIN` - /// itself.. + /// itself. #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] pub fn wrapping_div(self, rhs: Self) -> Self { @@ -478,8 +479,8 @@ macro_rules! int_impl { /// wrapping around at the boundary of the type. /// /// Such wrap-around never actually occurs mathematically; - /// implementation artifacts make `x % y` illegal for `MIN / - /// -1` on a signed type illegal (where `MIN` is the negative + /// implementation artifacts make `x % y` invalid for `MIN / + /// -1` on a signed type (where `MIN` is the negative /// minimal value). In such a case, this function returns `0`. #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] @@ -668,10 +669,12 @@ macro_rules! uint_impl { $mul_with_overflow:path) => { /// Returns the smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn min_value() -> Self { 0 } /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn max_value() -> Self { !0 } /// Converts a string slice in a given base to an integer. @@ -1029,7 +1032,7 @@ macro_rules! uint_impl { } } - /// Wrapping (modular) division. Computes `floor(self / other)`, + /// Wrapping (modular) division. Computes `self / other`, /// wrapping around at the boundary of the type. /// /// The only case where such wrapping can occur is when one @@ -1037,7 +1040,7 @@ macro_rules! uint_impl { /// negative minimal value for the type); this is equivalent /// to `-MIN`, a positive value that is too large to represent /// in the type. In such a case, this function returns `MIN` - /// itself.. + /// itself. #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] pub fn wrapping_div(self, rhs: Self) -> Self { @@ -1048,8 +1051,8 @@ macro_rules! uint_impl { /// wrapping around at the boundary of the type. /// /// Such wrap-around never actually occurs mathematically; - /// implementation artifacts make `x % y` illegal for `MIN / - /// -1` on a signed type illegal (where `MIN` is the negative + /// implementation artifacts make `x % y` invalid for `MIN / + /// -1` on a signed type (where `MIN` is the negative /// minimal value). In such a case, this function returns `0`. #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] @@ -1124,7 +1127,7 @@ macro_rules! uint_impl { acc } - /// Returns `true` iff `self == 2^k` for some `k`. + /// Returns `true` if and only if `self == 2^k` for some `k`. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_power_of_two(self) -> bool { @@ -1446,19 +1449,30 @@ fn from_str_radix(src: &str, radix: u32) -> Result { use self::IntErrorKind::*; use self::ParseIntError as PIE; + assert!(radix >= 2 && radix <= 36, "from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix); + if src.is_empty() { + return Err(PIE { kind: Empty }); + } + let is_signed_ty = T::from_u32(0) > T::min_value(); - match src.slice_shift_char() { - Some(('-', "")) => Err(PIE { kind: Empty }), - Some(('-', src)) if is_signed_ty => { + // all valid digits are ascii, so we will just iterate over the utf8 bytes + // and cast them to chars. .to_digit() will safely return None for anything + // other than a valid ascii digit for a the given radix, including the first-byte + // of multi-byte sequences + let src = src.as_bytes(); + + match (src[0], &src[1..]) { + (b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }), + (b'-', digits) if is_signed_ty => { // The number is negative let mut result = T::from_u32(0); - for c in src.chars() { - let x = match c.to_digit(radix) { + for &c in digits { + let x = match (c as char).to_digit(radix) { Some(x) => x, None => return Err(PIE { kind: InvalidDigit }), }; @@ -1473,11 +1487,14 @@ fn from_str_radix(src: &str, radix: u32) } Ok(result) }, - Some((_, _)) => { + (c, digits) => { // The number is signed - let mut result = T::from_u32(0); - for c in src.chars() { - let x = match c.to_digit(radix) { + let mut result = match (c as char).to_digit(radix) { + Some(x) => T::from_u32(x), + None => return Err(PIE { kind: InvalidDigit }), + }; + for &c in digits { + let x = match (c as char).to_digit(radix) { Some(x) => x, None => return Err(PIE { kind: InvalidDigit }), }; @@ -1491,8 +1508,7 @@ fn from_str_radix(src: &str, radix: u32) }; } Ok(result) - }, - None => Err(ParseIntError { kind: Empty }), + } } } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index 21635799a7..ecf7994484 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 16-bits integers (`u16` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u16")] uint_module! { u16, i16, 16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 7d52077050..b0682b55ac 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u32")] uint_module! { u32, i32, 32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index f10822077d..dbc6a64a90 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u64")] uint_module! { u64, i64, 64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 3d6922b07b..bf9347ca62 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -11,6 +11,5 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "u8")] uint_module! { u8, i8, 8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index 0719d7c17c..b31d6a73a7 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -14,14 +14,18 @@ macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => ( #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BITS : usize = $bits; #[unstable(feature = "num_bits_bytes", reason = "may want to be an associated function")] +#[allow(missing_docs)] pub const BYTES : usize = ($bits / 8); #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MIN: $T = 0 as $T; #[stable(feature = "rust1", since = "1.0.0")] +#[allow(missing_docs)] pub const MAX: $T = !0 as $T; ) } diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 6fd23425e4..67e3c954ab 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -11,6 +11,5 @@ //! Operations and constants for pointer-sized unsigned integers (`usize` type) #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "usize")] uint_module! { usize, isize, ::isize::BITS } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 748ed29e3a..2e3b34af51 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -119,6 +119,16 @@ macro_rules! wrapping_impl { } } + #[stable(feature = "wrapping_div", since = "1.3.0")] + impl Div for Wrapping<$t> { + type Output = Wrapping<$t>; + + #[inline(always)] + fn div(self, other: Wrapping<$t>) -> Wrapping<$t> { + Wrapping(self.0.wrapping_div(other.0)) + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl Not for Wrapping<$t> { type Output = Wrapping<$t>; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 48b1cbeef4..c1cf2230ac 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -351,8 +351,10 @@ pub trait Div { fn div(self, rhs: RHS) -> Self::Output; } -macro_rules! div_impl { +macro_rules! div_impl_integer { ($($t:ty)*) => ($( + /// This operation rounds towards zero, truncating any + /// fractional part of the exact result. #[stable(feature = "rust1", since = "1.0.0")] impl Div for $t { type Output = $t; @@ -365,7 +367,23 @@ macro_rules! div_impl { )*) } -div_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +div_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + +macro_rules! div_impl_float { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Div for $t { + type Output = $t; + + #[inline] + fn div(self, other: $t) -> $t { self / other } + } + + forward_ref_binop! { impl Div, div for $t, $t } + )*) +} + +div_impl_float! { f32 f64 } /// The `Rem` trait is used to specify the functionality of `%`. /// @@ -407,6 +425,8 @@ pub trait Rem { macro_rules! rem_impl { ($($t:ty)*) => ($( + /// This operation satisfies `n % d == n - (n / d) * d`. The + /// result has the same sign as the left operand. #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { type Output = $t; @@ -419,26 +439,40 @@ macro_rules! rem_impl { )*) } -macro_rules! rem_float_impl { - ($t:ty, $fmod:ident) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { - type Output = $t; +rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } - #[inline] - fn rem(self, other: $t) -> $t { - extern { fn $fmod(a: $t, b: $t) -> $t; } - unsafe { $fmod(self, other) } - } - } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f32 { + type Output = f32; + + // see notes in `core::f32::Float::floor` + #[inline] + #[cfg(target_env = "msvc")] + fn rem(self, other: f32) -> f32 { + (self as f64).rem(other as f64) as f32 + } - forward_ref_binop! { impl Rem, rem for $t, $t } + #[inline] + #[cfg(not(target_env = "msvc"))] + fn rem(self, other: f32) -> f32 { + extern { fn fmodf(a: f32, b: f32) -> f32; } + unsafe { fmodf(self, other) } } } -rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } -rem_float_impl! { f32, fmodf } -rem_float_impl! { f64, fmod } +#[stable(feature = "rust1", since = "1.0.0")] +impl Rem for f64 { + type Output = f64; + + #[inline] + fn rem(self, other: f64) -> f64 { + extern { fn fmod(a: f64, b: f64) -> f64; } + unsafe { fmod(self, other) } + } +} + +forward_ref_binop! { impl Rem, rem for f64, f64 } +forward_ref_binop! { impl Rem, rem for f32, f32 } /// The `Neg` trait is used to specify the functionality of unary `-`. /// @@ -483,7 +517,6 @@ pub trait Neg { macro_rules! neg_impl_core { ($id:ident => $body:expr, $($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] - #[allow(unsigned_negation)] impl Neg for $t { #[stable(feature = "rust1", since = "1.0.0")] type Output = $t; @@ -1024,6 +1057,10 @@ impl fmt::Debug for RangeTo { /// The `Deref` trait is used to specify the functionality of dereferencing /// operations like `*v`. /// +/// `Deref` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is accessible via dereferencing the @@ -1078,6 +1115,10 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// The `DerefMut` trait is used to specify the functionality of dereferencing /// mutably like `*v = 1;` /// +/// `DerefMut` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/deref-coercions.html +/// /// # Examples /// /// A struct with a single field which is modifiable via dereferencing the @@ -1233,3 +1274,120 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + +/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +#[unstable(feature = "placement_new_protocol")] +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `in (PLACE) EXPR`. +/// +/// `in (PLACE) EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +#[unstable(feature = "placement_new_protocol")] +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `in (PLACE) EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `in (PLACE) EXPR` + /// + /// Note that when `in (PLACE) EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +#[unstable(feature = "placement_new_protocol")] +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place: BoxPlace; + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +#[unstable(feature = "placement_new_protocol")] +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index c5203c5111..2235dc4af1 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -46,7 +46,7 @@ //! // The division was valid //! Some(x) => println!("Result: {}", x), //! // The division was invalid -//! None => println!("Cannot divide by 0") +//! None => println!("Cannot divide by 0"), //! } //! ``` //! @@ -75,7 +75,7 @@ //! fn check_optional(optional: &Option>) { //! match *optional { //! Some(ref p) => println!("have value {}", p), -//! None => println!("have no value") +//! None => println!("have no value"), //! } //! } //! ``` @@ -95,13 +95,13 @@ //! // Take a reference to the contained string //! match msg { //! Some(ref m) => println!("{}", *m), -//! None => () +//! None => (), //! } //! //! // Remove the contained string, destroying the Option //! let unwrapped_msg = match msg { //! Some(m) => m, -//! None => "default message" +//! None => "default message", //! }; //! ``` //! @@ -137,7 +137,7 @@ //! //! match name_of_biggest_animal { //! Some(name) => println!("the biggest animal is {}", name), -//! None => println!("there are no animals :(") +//! None => println!("there are no animals :("), //! } //! ``` @@ -198,7 +198,7 @@ impl Option { pub fn is_some(&self) -> bool { match *self { Some(_) => true, - None => false + None => false, } } @@ -244,7 +244,7 @@ impl Option { pub fn as_ref<'r>(&'r self) -> Option<&'r T> { match *self { Some(ref x) => Some(x), - None => None + None => None, } } @@ -265,7 +265,7 @@ impl Option { pub fn as_mut<'r>(&'r mut self) -> Option<&'r mut T> { match *self { Some(ref mut x) => Some(x), - None => None + None => None, } } @@ -274,7 +274,8 @@ impl Option { /// # Examples /// /// ``` - /// # #![feature(as_slice)] + /// #![feature(as_slice)] + /// /// let mut x = Some("Diamonds"); /// { /// let v = x.as_mut_slice(); @@ -376,7 +377,7 @@ impl Option { pub fn unwrap_or(self, def: T) -> T { match self { Some(x) => x, - None => def + None => def, } } @@ -394,7 +395,7 @@ impl Option { pub fn unwrap_or_else T>(self, f: F) -> T { match self { Some(x) => x, - None => f() + None => f(), } } @@ -420,7 +421,7 @@ impl Option { pub fn map U>(self, f: F) -> Option { match self { Some(x) => Some(f(x)), - None => None + None => None, } } @@ -464,7 +465,7 @@ impl Option { pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U { match self { Some(t) => f(t), - None => default() + None => default(), } } @@ -637,7 +638,7 @@ impl Option { pub fn or(self, optb: Option) -> Option { match self { Some(_) => self, - None => optb + None => optb, } } @@ -659,7 +660,7 @@ impl Option { pub fn or_else Option>(self, f: F) -> Option { match self { Some(_) => self, - None => f() + None => f(), } } @@ -736,7 +737,7 @@ impl Option { pub fn unwrap_or_default(self) -> T { match self { Some(x) => x, - None => Default::default() + None => Default::default(), } } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index f2792a525d..116c1dfaa3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -10,92 +10,17 @@ // FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory -//! Operations on raw pointers, `*const T`, and `*mut T`. +//! Raw, unsafe pointers, `*const T`, and `*mut T` //! -//! Working with raw pointers in Rust is uncommon, -//! typically limited to a few patterns. -//! -//! Use the `null` function to create null pointers, and the `is_null` method -//! of the `*const T` type to check for null. The `*const T` type also defines -//! the `offset` method, for pointer math. -//! -//! # Common ways to create raw pointers -//! -//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -//! -//! ``` -//! let my_num: i32 = 10; -//! let my_num_ptr: *const i32 = &my_num; -//! let mut my_speed: i32 = 88; -//! let my_speed_ptr: *mut i32 = &mut my_speed; -//! ``` -//! -//! To get a pointer to a boxed value, dereference the box: -//! -//! ``` -//! let my_num: Box = Box::new(10); -//! let my_num_ptr: *const i32 = &*my_num; -//! let mut my_speed: Box = Box::new(88); -//! let my_speed_ptr: *mut i32 = &mut *my_speed; -//! ``` -//! -//! This does not take ownership of the original allocation -//! and requires no resource management later, -//! but you must not use the pointer after its lifetime. -//! -//! ## 2. Consume a box (`Box`). -//! -//! The `into_raw` function consumes a box and returns -//! the raw pointer. It doesn't destroy `T` or deallocate any memory. -//! -//! ``` -//! # #![feature(box_raw)] -//! use std::boxed; -//! -//! unsafe { -//! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = boxed::into_raw(my_speed); -//! -//! // By taking ownership of the original `Box` though -//! // we are obligated to put it together later to be destroyed. -//! drop(Box::from_raw(my_speed)); -//! } -//! ``` -//! -//! Note that here the call to `drop` is for clarity - it indicates -//! that we are done with the given value and it should be destroyed. -//! -//! ## 3. Get it from C. -//! -//! ``` -//! # #![feature(libc)] -//! extern crate libc; -//! -//! use std::mem; -//! -//! fn main() { -//! unsafe { -//! let my_num: *mut i32 = libc::malloc(mem::size_of::() as libc::size_t) as *mut i32; -//! if my_num.is_null() { -//! panic!("failed to allocate memory"); -//! } -//! libc::free(my_num as *mut libc::c_void); -//! } -//! } -//! ``` -//! -//! Usually you wouldn't literally use `malloc` and `free` from Rust, -//! but C APIs hand out a lot of pointers generally, so are a common source -//! of raw pointers in Rust. +//! *[See also the pointer primitive types](../primitive.pointer.html).* #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "pointer")] use mem; use clone::Clone; use intrinsics; use ops::Deref; -use core::fmt; +use fmt; use option::Option::{self, Some, None}; use marker::{PhantomData, Send, Sized, Sync}; use nonzero::NonZero; @@ -206,6 +131,9 @@ pub unsafe fn read(src: *const T) -> T { #[inline(always)] #[unstable(feature = "read_and_zero", reason = "may play a larger role in std::ptr future extensions")] +#[deprecated(since = "1.3.0", + reason = "a \"zero value\" will soon not actually exist for all \ + types once dynamic drop has been implemented")] pub unsafe fn read_and_zero(dest: *mut T) -> T { // Copy the data out from `dest`: let tmp = read(&*dest); diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 43535ddd1d..f0bac1bfef 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -49,7 +49,8 @@ use mem; /// # Examples /// /// ``` -/// # #![feature(raw)] +/// #![feature(raw)] +/// /// use std::raw::{self, Repr}; /// /// let slice: &[u16] = &[1, 2, 3, 4]; @@ -98,7 +99,8 @@ impl Clone for Slice { /// # Examples /// /// ``` -/// # #![feature(raw)] +/// #![feature(raw)] +/// /// use std::mem; /// use std::raw; /// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index d87c1020dc..100cf0779b 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -420,7 +420,8 @@ impl Result { /// Converts from `Result` to `&mut [T]` (without copying) /// /// ``` - /// # #![feature(as_slice)] + /// #![feature(as_slice)] + /// /// let mut x: Result<&str, u32> = Ok("Gold"); /// { /// let v = x.as_mut_slice(); @@ -744,7 +745,7 @@ impl Result { /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure` /// ``` #[inline] - #[unstable(feature = "result_expect", reason = "newly introduced")] + #[unstable(feature = "result_expect", reason = "newly introduced", issue = "27277")] pub fn expect(self, msg: &str) -> T { match self { Ok(t) => t, diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index 7ecd08bea3..d0205fc9b1 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -19,7 +19,8 @@ //! provided beyond this module. //! //! ```rust -//! # #![feature(core_simd)] +//! #![feature(core_simd)] +//! //! fn main() { //! use std::simd::f32x4; //! let a = f32x4(40.0, 41.0, 42.0, 43.0); diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index a8c995f37c..f765cdc54d 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -13,7 +13,6 @@ //! For more details `std::slice`. #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "slice")] // How this module is organized. // @@ -83,6 +82,8 @@ pub trait SliceExt { fn first<'a>(&'a self) -> Option<&'a Self::Item>; fn tail<'a>(&'a self) -> &'a [Self::Item]; fn init<'a>(&'a self) -> &'a [Self::Item]; + fn split_first<'a>(&'a self) -> Option<(&'a Self::Item, &'a [Self::Item])>; + fn split_last<'a>(&'a self) -> Option<(&'a Self::Item, &'a [Self::Item])>; fn last<'a>(&'a self) -> Option<&'a Self::Item>; unsafe fn get_unchecked<'a>(&'a self, index: usize) -> &'a Self::Item; fn as_ptr(&self) -> *const Self::Item; @@ -95,6 +96,8 @@ pub trait SliceExt { fn first_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>; fn tail_mut<'a>(&'a mut self) -> &'a mut [Self::Item]; fn init_mut<'a>(&'a mut self) -> &'a mut [Self::Item]; + fn split_first_mut<'a>(&'a mut self) -> Option<(&'a mut Self::Item, &'a mut [Self::Item])>; + fn split_last_mut<'a>(&'a mut self) -> Option<(&'a mut Self::Item, &'a mut [Self::Item])>; fn last_mut<'a>(&'a mut self) -> Option<&'a mut Self::Item>; fn split_mut<'a, P>(&'a mut self, pred: P) -> SplitMut<'a, Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -238,8 +241,17 @@ impl SliceExt for [T] { fn tail(&self) -> &[T] { &self[1..] } #[inline] - fn init(&self) -> &[T] { - &self[..self.len() - 1] + fn split_first(&self) -> Option<(&T, &[T])> { + if self.is_empty() { None } else { Some((&self[0], &self[1..])) } + } + + #[inline] + fn init(&self) -> &[T] { &self[..self.len() - 1] } + + #[inline] + fn split_last(&self) -> Option<(&T, &[T])> { + let len = self.len(); + if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } } #[inline] @@ -288,11 +300,12 @@ impl SliceExt for [T] { #[inline] fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + assert!(mid <= len); unsafe { - let self2: &mut [T] = mem::transmute_copy(&self); - - (ops::IndexMut::index_mut(self, ops::RangeTo { end: mid } ), - ops::IndexMut::index_mut(self2, ops::RangeFrom { start: mid } )) + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -328,8 +341,14 @@ impl SliceExt for [T] { } #[inline] - fn tail_mut(&mut self) -> &mut [T] { - &mut self[1 ..] + fn tail_mut(&mut self) -> &mut [T] { &mut self[1 ..] } + + #[inline] + fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + if self.is_empty() { None } else { + let split = self.split_at_mut(1); + Some((&mut split.0[0], split.1)) + } } #[inline] @@ -338,6 +357,15 @@ impl SliceExt for [T] { &mut self[.. (len - 1)] } + #[inline] + fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + let len = self.len(); + if len == 0 { None } else { + let split = self.split_at_mut(len - 1); + Some((&mut split.1[0], split.0)) + } + } + #[inline] fn split_mut<'a, P>(&'a mut self, pred: P) -> SplitMut<'a, T, P> where P: FnMut(&T) -> bool { SplitMut { v: self, pred: pred, finished: false } @@ -1368,10 +1396,14 @@ pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] { /// /// The `len` argument is the number of **elements**, not the number of bytes. /// +/// # Unsafety +/// /// This function is unsafe as there is no guarantee that the given pointer is /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// +/// `p` must be non-null, even for zero-length slices. +/// /// # Caveat /// /// The lifetime for the returned slice is inferred from its usage. To @@ -1459,12 +1491,30 @@ pub mod bytes { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[B]> for [A] where A: PartialEq { fn eq(&self, other: &[B]) -> bool { - self.len() == other.len() && - order::eq(self.iter(), other.iter()) + if self.len() != other.len() { + return false; + } + + for i in 0..self.len() { + if !self[i].eq(&other[i]) { + return false; + } + } + + true } fn ne(&self, other: &[B]) -> bool { - self.len() != other.len() || - order::ne(self.iter(), other.iter()) + if self.len() != other.len() { + return true; + } + + for i in 0..self.len() { + if self[i].ne(&other[i]) { + return true; + } + } + + false } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 5a621176c4..4f0b881c5c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -12,16 +12,14 @@ //! //! For more details, see std::str -#![doc(primitive = "str")] #![stable(feature = "rust1", since = "1.0.0")] -use self::OldSearcher::{TwoWay, TwoWayLong}; use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::CharExt; use clone::Clone; -use cmp::{self, Eq}; +use cmp::Eq; use convert::AsRef; use default::Default; use fmt; @@ -33,7 +31,6 @@ use option::Option::{self, None, Some}; use raw::{Repr, Slice}; use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; -use usize; pub mod pattern; @@ -638,10 +635,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split()`."] + /// Created with the method `.split()`. struct Split; reverse: - #[doc="Created with the method `.rsplit()`."] + /// Created with the method `.rsplit()`. struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -652,10 +649,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - #[doc="Created with the method `.split_terminator()`."] + /// Created with the method `.split_terminator()`. struct SplitTerminator; reverse: - #[doc="Created with the method `.rsplit_terminator()`."] + /// Created with the method `.rsplit_terminator()`. struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -698,10 +695,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.splitn()`."] + /// Created with the method `.splitn()`. struct SplitN; reverse: - #[doc="Created with the method `.rsplitn()`."] + /// Created with the method `.rsplitn()`. struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -732,10 +729,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.match_indices()`."] + /// Created with the method `.match_indices()`. struct MatchIndices; reverse: - #[doc="Created with the method `.rmatch_indices()`."] + /// Created with the method `.rmatch_indices()`. struct RMatchIndices; stability: #[unstable(feature = "str_match_indices", @@ -773,10 +770,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - #[doc="Created with the method `.matches()`."] + /// Created with the method `.matches()`. struct Matches; reverse: - #[doc="Created with the method `.rmatches()`."] + /// Created with the method `.rmatches()`. struct RMatches; stability: #[stable(feature = "str_matches", since = "1.2.0")] @@ -870,311 +867,16 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> { } } -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using two-way search -#[derive(Clone)] -struct TwoWaySearcher { - // constants - crit_pos: usize, - period: usize, - byteset: u64, - - // variables - position: usize, - memory: usize -} - -/* - This is the Two-Way search algorithm, which was introduced in the paper: - Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. - - Here's some background information. - - A *word* is a string of symbols. The *length* of a word should be a familiar - notion, and here we denote it for any word x by |x|. - (We also allow for the possibility of the *empty word*, a word of length zero). - - If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a - *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. - For example, both 1 and 2 are periods for the string "aa". As another example, - the only period of the string "abcd" is 4. - - We denote by period(x) the *smallest* period of x (provided that x is non-empty). - This is always well-defined since every non-empty word x has at least one period, - |x|. We sometimes call this *the period* of x. - - If u, v and x are words such that x = uv, where uv is the concatenation of u and - v, then we say that (u, v) is a *factorization* of x. - - Let (u, v) be a factorization for a word x. Then if w is a non-empty word such - that both of the following hold - - - either w is a suffix of u or u is a suffix of w - - either w is a prefix of v or v is a prefix of w - - then w is said to be a *repetition* for the factorization (u, v). - - Just to unpack this, there are four possibilities here. Let w = "abc". Then we - might have: - - - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") - - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") - - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") - - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") - - Note that the word vu is a repetition for any factorization (u,v) of x = uv, - so every factorization has at least one repetition. - - If x is a string and (u, v) is a factorization for x, then a *local period* for - (u, v) is an integer r such that there is some word w such that |w| = r and w is - a repetition for (u, v). - - We denote by local_period(u, v) the smallest local period of (u, v). We sometimes - call this *the local period* of (u, v). Provided that x = uv is non-empty, this - is well-defined (because each non-empty word has at least one factorization, as - noted above). - - It can be proven that the following is an equivalent definition of a local period - for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for - all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are - defined. (i.e. i > 0 and i + r < |x|). - - Using the above reformulation, it is easy to prove that - - 1 <= local_period(u, v) <= period(uv) - - A factorization (u, v) of x such that local_period(u,v) = period(x) is called a - *critical factorization*. - - The algorithm hinges on the following theorem, which is stated without proof: - - **Critical Factorization Theorem** Any word x has at least one critical - factorization (u, v) such that |u| < period(x). - - The purpose of maximal_suffix is to find such a critical factorization. - -*/ -impl TwoWaySearcher { - #[allow(dead_code)] - fn new(needle: &[u8]) -> TwoWaySearcher { - let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); - let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); - - let (crit_pos, period) = - if crit_pos_false > crit_pos_true { - (crit_pos_false, period_false) - } else { - (crit_pos_true, period_true) - }; - - // This isn't in the original algorithm, as far as I'm aware. - let byteset = needle.iter() - .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); - - // A particularly readable explanation of what's going on here can be found - // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically - // see the code for "Algorithm CP" on p. 323. - // - // What's going on is we have some critical factorization (u, v) of the - // needle, and we want to determine whether u is a suffix of - // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use - // "Algorithm CP2", which is optimized for when the period of the needle - // is large. - if &needle[..crit_pos] == &needle[period.. period + crit_pos] { - TwoWaySearcher { - crit_pos: crit_pos, - period: period, - byteset: byteset, - - position: 0, - memory: 0 - } - } else { - TwoWaySearcher { - crit_pos: crit_pos, - period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, - byteset: byteset, - - position: 0, - memory: usize::MAX // Dummy value to signify that the period is long - } - } - } - - // One of the main ideas of Two-Way is that we factorize the needle into - // two halves, (u, v), and begin trying to find v in the haystack by scanning - // left to right. If v matches, we try to match u by scanning right to left. - // How far we can jump when we encounter a mismatch is all based on the fact - // that (u, v) is a critical factorization for the needle. - #[inline] - fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) - -> Option<(usize, usize)> { - 'search: loop { - // Check that we have room to search in - if self.position + needle.len() > haystack.len() { - return None; - } - - // Quickly skip by large portions unrelated to our substring - if (self.byteset >> - ((haystack[self.position + needle.len() - 1] & 0x3f) - as usize)) & 1 == 0 { - self.position += needle.len(); - if !long_period { - self.memory = 0; - } - continue 'search; - } - - // See if the right part of the needle matches - let start = if long_period { self.crit_pos } - else { cmp::max(self.crit_pos, self.memory) }; - for i in start..needle.len() { - if needle[i] != haystack[self.position + i] { - self.position += i - self.crit_pos + 1; - if !long_period { - self.memory = 0; - } - continue 'search; - } - } - - // See if the left part of the needle matches - let start = if long_period { 0 } else { self.memory }; - for i in (start..self.crit_pos).rev() { - if needle[i] != haystack[self.position + i] { - self.position += self.period; - if !long_period { - self.memory = needle.len() - self.period; - } - continue 'search; - } - } - - // We have found a match! - let match_pos = self.position; - self.position += needle.len(); // add self.period for all matches - if !long_period { - self.memory = 0; // set to needle.len() - self.period for all matches - } - return Some((match_pos, match_pos + needle.len())); - } - } - - // Computes a critical factorization (u, v) of `arr`. - // Specifically, returns (i, p), where i is the starting index of v in some - // critical factorization (u, v) and p = period(v) - #[inline] - #[allow(dead_code)] - #[allow(deprecated)] - fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { - let mut left: usize = !0; // Corresponds to i in the paper - let mut right = 0; // Corresponds to j in the paper - let mut offset = 1; // Corresponds to k in the paper - let mut period = 1; // Corresponds to p in the paper - - while right + offset < arr.len() { - let a; - let b; - if reversed { - a = arr[left.wrapping_add(offset)]; - b = arr[right + offset]; - } else { - a = arr[right + offset]; - b = arr[left.wrapping_add(offset)]; - } - if a < b { - // Suffix is smaller, period is entire prefix so far. - right += offset; - offset = 1; - period = right.wrapping_sub(left); - } else if a == b { - // Advance through repetition of the current period. - if offset == period { - right += offset; - offset = 1; - } else { - offset += 1; - } - } else { - // Suffix is larger, start over from current location. - left = right; - right += 1; - offset = 1; - period = 1; - } - } - (left.wrapping_add(1), period) - } -} - -/// The internal state of an iterator that searches for matches of a substring -/// within a larger string using a dynamically chosen search algorithm -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -enum OldSearcher { - TwoWay(TwoWaySearcher), - TwoWayLong(TwoWaySearcher), -} - -impl OldSearcher { - #[allow(dead_code)] - fn new(haystack: &[u8], needle: &[u8]) -> OldSearcher { - if needle.is_empty() { - // Handle specially - unimplemented!() - // FIXME: Tune this. - // FIXME(#16715): This unsigned integer addition will probably not - // overflow because that would mean that the memory almost solely - // consists of the needle. Needs #16715 to be formally fixed. - } else if needle.len() + 20 > haystack.len() { - // Use naive searcher - unimplemented!() - } else { - let searcher = TwoWaySearcher::new(needle); - if searcher.memory == usize::MAX { // If the period is long - TwoWayLong(searcher) - } else { - TwoWay(searcher) - } - } - } -} - -#[derive(Clone)] -// NB: This is kept around for convenience because -// it is planned to be used again in the future -struct OldMatchIndices<'a, 'b> { - // constants - haystack: &'a str, - needle: &'b str, - searcher: OldSearcher -} - -impl<'a, 'b> OldMatchIndices<'a, 'b> { - #[inline] - #[allow(dead_code)] - fn next(&mut self) -> Option<(usize, usize)> { - match self.searcher { - TwoWay(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), false), - TwoWayLong(ref mut searcher) - => searcher.next(self.haystack.as_bytes(), self.needle.as_bytes(), true), - } - } -} - /* Section: Comparing strings */ -// share the implementation of the lang-item vs. non-lang-item -// eq_slice. +/// Bytewise slice equality /// NOTE: This function is (ab)used in rustc::middle::trans::_match /// to compare &[u8] byte slices that are not necessarily valid UTF-8. +#[lang = "str_eq"] #[inline] -fn eq_slice_(a: &str, b: &str) -> bool { +fn eq_slice(a: &str, b: &str) -> bool { // NOTE: In theory n should be libc::size_t and not usize, but libc is not available here #[allow(improper_ctypes)] extern { fn memcmp(s1: *const i8, s2: *const i8, n: usize) -> i32; } @@ -1185,15 +887,6 @@ fn eq_slice_(a: &str, b: &str) -> bool { } } -/// Bytewise slice equality -/// NOTE: This function is (ab)used in rustc::middle::trans::_match -/// to compare &[u8] byte slices that are not necessarily valid UTF-8. -#[lang = "str_eq"] -#[inline] -fn eq_slice(a: &str, b: &str) -> bool { - eq_slice_(a, b) -} - /* Section: Misc */ @@ -1413,6 +1106,23 @@ mod traits { } } + /// Returns a mutable slice of the given string from the byte range + /// [`begin`..`end`). + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::Range) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if index.start <= index.end && + self.is_char_boundary(index.start) && + self.is_char_boundary(index.end) { + unsafe { self.slice_mut_unchecked(index.start, index.end) } + } else { + super::slice_error_fail(self, index.start, index.end) + } + } + } + /// Returns a slice of the string from the beginning to byte /// `end`. /// @@ -1435,6 +1145,21 @@ mod traits { } } + /// Returns a mutable slice of the string from the beginning to byte + /// `end`. + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.end) { + unsafe { self.slice_mut_unchecked(0, index.end) } + } else { + super::slice_error_fail(self, 0, index.end) + } + } + } + /// Returns a slice of the string from `begin` to its end. /// /// Equivalent to `self[begin .. self.len()]`. @@ -1456,6 +1181,21 @@ mod traits { } } + /// Returns a slice of the string from `begin` to its end. + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut> for str { + #[inline] + fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(index.start) { + let len = self.len(); + unsafe { self.slice_mut_unchecked(index.start, len) } + } else { + super::slice_error_fail(self, index.start, self.len()) + } + } + } + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index for str { type Output = str; @@ -1465,6 +1205,14 @@ mod traits { self } } + + #[stable(feature = "derefmut_for_string", since = "1.2.0")] + impl ops::IndexMut for str { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { + self + } + } } /// Methods for string slices @@ -1501,6 +1249,7 @@ pub trait StrExt { fn char_len(&self) -> usize; fn slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str; unsafe fn slice_unchecked<'a>(&'a self, begin: usize, end: usize) -> &'a str; + unsafe fn slice_mut_unchecked<'a>(&'a mut self, begin: usize, end: usize) -> &'a mut str; fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool where P::Searcher: ReverseSearcher<'a>; @@ -1520,6 +1269,7 @@ pub trait StrExt { where P::Searcher: ReverseSearcher<'a>; fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; fn split_at(&self, mid: usize) -> (&str, &str); + fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str); fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>; fn subslice_offset(&self, inner: &str) -> usize; fn as_ptr(&self) -> *const u8; @@ -1676,6 +1426,14 @@ impl StrExt for str { }) } + #[inline] + unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + mem::transmute(Slice { + data: self.as_ptr().offset(begin as isize), + len: end - begin, + }) + } + #[inline] fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { pat.is_prefix_of(self) @@ -1824,6 +1582,20 @@ impl StrExt for str { } } + fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + let len = self.len(); + unsafe { + let self2: &mut str = mem::transmute_copy(&self); + (self.slice_mut_unchecked(0, mid), + self2.slice_mut_unchecked(mid, len)) + } + } else { + slice_error_fail(self, 0, mid) + } + } + #[inline] fn slice_shift_char(&self) -> Option<(char, &str)> { if self.is_empty() { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 8bdbab5521..2b3fc39fc8 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -17,6 +17,8 @@ reason = "API not fully fleshed out and ready to be stabilized")] use prelude::*; +use cmp; +use usize; // Pattern @@ -341,148 +343,6 @@ unsafe impl<'a, C: CharEq> ReverseSearcher<'a> for CharEqSearcher<'a, C> { impl<'a, C: CharEq> DoubleEndedSearcher<'a> for CharEqSearcher<'a, C> {} -///////////////////////////////////////////////////////////////////////////// -// Impl for &str -///////////////////////////////////////////////////////////////////////////// - -// Todo: Optimize the naive implementation here - -/// Associated type for `<&str as Pattern<'a>>::Searcher`. -#[derive(Clone)] -pub struct StrSearcher<'a, 'b> { - haystack: &'a str, - needle: &'b str, - start: usize, - end: usize, - state: State, -} - -#[derive(Clone, PartialEq)] -enum State { Done, NotDone, Reject(usize, usize) } -impl State { - #[inline] fn done(&self) -> bool { *self == State::Done } - #[inline] fn take(&mut self) -> State { ::mem::replace(self, State::NotDone) } -} - -/// Non-allocating substring search. -/// -/// Will handle the pattern `""` as returning empty matches at each utf8 -/// boundary. -impl<'a, 'b> Pattern<'a> for &'b str { - type Searcher = StrSearcher<'a, 'b>; - - #[inline] - fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { - StrSearcher { - haystack: haystack, - needle: self, - start: 0, - end: haystack.len(), - state: State::NotDone, - } - } -} - -unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn haystack(&self) -> &'a str { - self.haystack - } - - #[inline] - fn next(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Forward step for empty needle - let current_start = m.start; - if !m.state.done() { - m.start = m.haystack.char_range_at(current_start).next; - m.state = State::Reject(current_start, m.start); - } - SearchStep::Match(current_start, current_start) - }, - |m: &mut StrSearcher| { - // Forward step for nonempty needle - let current_start = m.start; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.start .. m.start + m.needle.len()]; - if possible_match == m.needle.as_bytes() { - m.start += m.needle.len(); - SearchStep::Match(current_start, m.start) - } else { - // Skip a char - let haystack_suffix = &m.haystack[m.start..]; - m.start += haystack_suffix.chars().next().unwrap().len_utf8(); - SearchStep::Reject(current_start, m.start) - } - }) - } -} - -unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { - #[inline] - fn next_back(&mut self) -> SearchStep { - str_search_step(self, - |m: &mut StrSearcher| { - // Backward step for empty needle - let current_end = m.end; - if !m.state.done() { - m.end = m.haystack.char_range_at_reverse(current_end).next; - m.state = State::Reject(m.end, current_end); - } - SearchStep::Match(current_end, current_end) - }, - |m: &mut StrSearcher| { - // Backward step for nonempty needle - let current_end = m.end; - // Compare byte window because this might break utf8 boundaries - let possible_match = &m.haystack.as_bytes()[m.end - m.needle.len() .. m.end]; - if possible_match == m.needle.as_bytes() { - m.end -= m.needle.len(); - SearchStep::Match(m.end, current_end) - } else { - // Skip a char - let haystack_prefix = &m.haystack[..m.end]; - m.end -= haystack_prefix.chars().rev().next().unwrap().len_utf8(); - SearchStep::Reject(m.end, current_end) - } - }) - } -} - -// Helper function for encapsulating the common control flow -// of doing a search step from the front or doing a search step from the back -fn str_search_step(mut m: &mut StrSearcher, - empty_needle_step: F, - nonempty_needle_step: G) -> SearchStep - where F: FnOnce(&mut StrSearcher) -> SearchStep, - G: FnOnce(&mut StrSearcher) -> SearchStep -{ - if m.state.done() { - SearchStep::Done - } else if m.needle.is_empty() && m.start <= m.end { - // Case for needle == "" - if let State::Reject(a, b) = m.state.take() { - SearchStep::Reject(a, b) - } else { - if m.start == m.end { - m.state = State::Done; - } - empty_needle_step(&mut m) - } - } else if m.start + m.needle.len() <= m.end { - // Case for needle != "" - nonempty_needle_step(&mut m) - } else if m.start < m.end { - // Remaining slice shorter than needle, reject it - m.state = State::Done; - SearchStep::Reject(m.start, m.end) - } else { - m.state = State::Done; - SearchStep::Done - } -} - ///////////////////////////////////////////////////////////////////////////// macro_rules! pattern_methods { @@ -633,3 +493,578 @@ impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { impl<'a, 'b> Pattern<'a> for &'b &'b str { pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); } + +///////////////////////////////////////////////////////////////////////////// +// Impl for &str +///////////////////////////////////////////////////////////////////////////// + +/// Non-allocating substring search. +/// +/// Will handle the pattern `""` as returning empty matches at each character +/// boundary. +impl<'a, 'b> Pattern<'a> for &'b str { + type Searcher = StrSearcher<'a, 'b>; + + #[inline] + fn into_searcher(self, haystack: &'a str) -> StrSearcher<'a, 'b> { + StrSearcher::new(haystack, self) + } + + /// Checks whether the pattern matches at the front of the haystack + #[inline] + fn is_prefix_of(self, haystack: &'a str) -> bool { + haystack.is_char_boundary(self.len()) && + self == &haystack[..self.len()] + } + + /// Checks whether the pattern matches at the back of the haystack + #[inline] + fn is_suffix_of(self, haystack: &'a str) -> bool { + self.len() <= haystack.len() && + haystack.is_char_boundary(haystack.len() - self.len()) && + self == &haystack[haystack.len() - self.len()..] + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Two Way substring searcher +///////////////////////////////////////////////////////////////////////////// + +#[derive(Clone, Debug)] +/// Associated type for `<&str as Pattern<'a>>::Searcher`. +pub struct StrSearcher<'a, 'b> { + haystack: &'a str, + needle: &'b str, + + searcher: StrSearcherImpl, +} + +#[derive(Clone, Debug)] +enum StrSearcherImpl { + Empty(EmptyNeedle), + TwoWay(TwoWaySearcher), +} + +#[derive(Clone, Debug)] +struct EmptyNeedle { + position: usize, + end: usize, + is_match_fw: bool, + is_match_bw: bool, +} + +impl<'a, 'b> StrSearcher<'a, 'b> { + fn new(haystack: &'a str, needle: &'b str) -> StrSearcher<'a, 'b> { + if needle.is_empty() { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::Empty(EmptyNeedle { + position: 0, + end: haystack.len(), + is_match_fw: true, + is_match_bw: true, + }), + } + } else { + StrSearcher { + haystack: haystack, + needle: needle, + searcher: StrSearcherImpl::TwoWay( + TwoWaySearcher::new(needle.as_bytes(), haystack.len()) + ), + } + } + } +} + +unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { + fn haystack(&self) -> &'a str { self.haystack } + + #[inline] + fn next(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + // empty needle rejects every char and matches every empty string between them + let is_match = searcher.is_match_fw; + searcher.is_match_fw = !searcher.is_match_fw; + let pos = searcher.position; + match self.haystack[pos..].chars().next() { + _ if is_match => SearchStep::Match(pos, pos), + None => SearchStep::Done, + Some(ch) => { + searcher.position += ch.len_utf8(); + SearchStep::Reject(pos, searcher.position) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + // TwoWaySearcher produces valid *Match* indices that split at char boundaries + // as long as it does correct matching and that haystack and needle are + // valid UTF-8 + // *Rejects* from the algorithm can fall on any indices, but we will walk them + // manually to the next character boundary, so that they are utf-8 safe. + if searcher.position == self.haystack.len() { + return SearchStep::Done; + } + let is_long = searcher.memory == usize::MAX; + match searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + is_long) + { + SearchStep::Reject(a, mut b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(b) { + b += 1; + } + searcher.position = cmp::max(b, searcher.position); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline(always)] + fn next_match(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + let is_long = searcher.memory == usize::MAX; + if is_long { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + true) + } else { + searcher.next::(self.haystack.as_bytes(), + self.needle.as_bytes(), + false) + } + } + } + } + +} +unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { + #[inline] + fn next_back(&mut self) -> SearchStep { + match self.searcher { + StrSearcherImpl::Empty(ref mut searcher) => { + let is_match = searcher.is_match_bw; + searcher.is_match_bw = !searcher.is_match_bw; + let end = searcher.end; + match self.haystack[..end].chars().next_back() { + _ if is_match => SearchStep::Match(end, end), + None => SearchStep::Done, + Some(ch) => { + searcher.end -= ch.len_utf8(); + SearchStep::Reject(searcher.end, end) + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + if searcher.end == 0 { + return SearchStep::Done; + } + match searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + { + SearchStep::Reject(mut a, b) => { + // skip to next char boundary + while !self.haystack.is_char_boundary(a) { + a -= 1; + } + searcher.end = cmp::min(a, searcher.end); + SearchStep::Reject(a, b) + } + otherwise => otherwise, + } + } + } + } + + #[inline] + fn next_match_back(&mut self) -> Option<(usize, usize)> { + match self.searcher { + StrSearcherImpl::Empty(..) => { + loop { + match self.next_back() { + SearchStep::Match(a, b) => return Some((a, b)), + SearchStep::Done => return None, + SearchStep::Reject(..) => { } + } + } + } + StrSearcherImpl::TwoWay(ref mut searcher) => { + searcher.next_back::(self.haystack.as_bytes(), + self.needle.as_bytes()) + } + } + } +} + +/// The internal state of an iterator that searches for matches of a substring +/// within a larger string using two-way search +#[derive(Clone, Debug)] +struct TwoWaySearcher { + // constants + crit_pos: usize, + period: usize, + byteset: u64, + + // variables + position: usize, + end: usize, + memory: usize +} + +/* + This is the Two-Way search algorithm, which was introduced in the paper: + Crochemore, M., Perrin, D., 1991, Two-way string-matching, Journal of the ACM 38(3):651-675. + + Here's some background information. + + A *word* is a string of symbols. The *length* of a word should be a familiar + notion, and here we denote it for any word x by |x|. + (We also allow for the possibility of the *empty word*, a word of length zero). + + If x is any non-empty word, then an integer p with 0 < p <= |x| is said to be a + *period* for x iff for all i with 0 <= i <= |x| - p - 1, we have x[i] == x[i+p]. + For example, both 1 and 2 are periods for the string "aa". As another example, + the only period of the string "abcd" is 4. + + We denote by period(x) the *smallest* period of x (provided that x is non-empty). + This is always well-defined since every non-empty word x has at least one period, + |x|. We sometimes call this *the period* of x. + + If u, v and x are words such that x = uv, where uv is the concatenation of u and + v, then we say that (u, v) is a *factorization* of x. + + Let (u, v) be a factorization for a word x. Then if w is a non-empty word such + that both of the following hold + + - either w is a suffix of u or u is a suffix of w + - either w is a prefix of v or v is a prefix of w + + then w is said to be a *repetition* for the factorization (u, v). + + Just to unpack this, there are four possibilities here. Let w = "abc". Then we + might have: + + - w is a suffix of u and w is a prefix of v. ex: ("lolabc", "abcde") + - w is a suffix of u and v is a prefix of w. ex: ("lolabc", "ab") + - u is a suffix of w and w is a prefix of v. ex: ("bc", "abchi") + - u is a suffix of w and v is a prefix of w. ex: ("bc", "a") + + Note that the word vu is a repetition for any factorization (u,v) of x = uv, + so every factorization has at least one repetition. + + If x is a string and (u, v) is a factorization for x, then a *local period* for + (u, v) is an integer r such that there is some word w such that |w| = r and w is + a repetition for (u, v). + + We denote by local_period(u, v) the smallest local period of (u, v). We sometimes + call this *the local period* of (u, v). Provided that x = uv is non-empty, this + is well-defined (because each non-empty word has at least one factorization, as + noted above). + + It can be proven that the following is an equivalent definition of a local period + for a factorization (u, v): any positive integer r such that x[i] == x[i+r] for + all i such that |u| - r <= i <= |u| - 1 and such that both x[i] and x[i+r] are + defined. (i.e. i > 0 and i + r < |x|). + + Using the above reformulation, it is easy to prove that + + 1 <= local_period(u, v) <= period(uv) + + A factorization (u, v) of x such that local_period(u,v) = period(x) is called a + *critical factorization*. + + The algorithm hinges on the following theorem, which is stated without proof: + + **Critical Factorization Theorem** Any word x has at least one critical + factorization (u, v) such that |u| < period(x). + + The purpose of maximal_suffix is to find such a critical factorization. + +*/ +impl TwoWaySearcher { + fn new(needle: &[u8], end: usize) -> TwoWaySearcher { + let (crit_pos_false, period_false) = TwoWaySearcher::maximal_suffix(needle, false); + let (crit_pos_true, period_true) = TwoWaySearcher::maximal_suffix(needle, true); + + let (crit_pos, period) = + if crit_pos_false > crit_pos_true { + (crit_pos_false, period_false) + } else { + (crit_pos_true, period_true) + }; + + // This isn't in the original algorithm, as far as I'm aware. + let byteset = needle.iter() + .fold(0, |a, &b| (1 << ((b & 0x3f) as usize)) | a); + + // A particularly readable explanation of what's going on here can be found + // in Crochemore and Rytter's book "Text Algorithms", ch 13. Specifically + // see the code for "Algorithm CP" on p. 323. + // + // What's going on is we have some critical factorization (u, v) of the + // needle, and we want to determine whether u is a suffix of + // &v[..period]. If it is, we use "Algorithm CP1". Otherwise we use + // "Algorithm CP2", which is optimized for when the period of the needle + // is large. + if &needle[..crit_pos] == &needle[period.. period + crit_pos] { + // short period case + TwoWaySearcher { + crit_pos: crit_pos, + period: period, + byteset: byteset, + + position: 0, + end: end, + memory: 0 + } + } else { + // long period case + // we have an approximation to the actual period, and don't use memory. + TwoWaySearcher { + crit_pos: crit_pos, + period: cmp::max(crit_pos, needle.len() - crit_pos) + 1, + byteset: byteset, + + position: 0, + end: end, + memory: usize::MAX // Dummy value to signify that the period is long + } + } + } + + #[inline(always)] + fn byteset_contains(&self, byte: u8) -> bool { + (self.byteset >> ((byte & 0x3f) as usize)) & 1 != 0 + } + + // One of the main ideas of Two-Way is that we factorize the needle into + // two halves, (u, v), and begin trying to find v in the haystack by scanning + // left to right. If v matches, we try to match u by scanning right to left. + // How far we can jump when we encounter a mismatch is all based on the fact + // that (u, v) is a critical factorization for the needle. + #[inline(always)] + fn next(&mut self, haystack: &[u8], needle: &[u8], long_period: bool) + -> S::Output + where S: TwoWayStrategy + { + // `next()` uses `self.position` as its cursor + let old_pos = self.position; + 'search: loop { + // Check that we have room to search in + if needle.len() > haystack.len() - self.position { + self.position = haystack.len(); + return S::rejecting(old_pos, self.position); + } + + if S::use_early_reject() && old_pos != self.position { + return S::rejecting(old_pos, self.position); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.position + needle.len() - 1]) { + self.position += needle.len(); + if !long_period { + self.memory = 0; + } + continue 'search; + } + + // See if the right part of the needle matches + let start = if long_period { self.crit_pos } + else { cmp::max(self.crit_pos, self.memory) }; + for i in start..needle.len() { + if needle[i] != haystack[self.position + i] { + self.position += i - self.crit_pos + 1; + if !long_period { + self.memory = 0; + } + continue 'search; + } + } + + // See if the left part of the needle matches + let start = if long_period { 0 } else { self.memory }; + for i in (start..self.crit_pos).rev() { + if needle[i] != haystack[self.position + i] { + self.position += self.period; + if !long_period { + self.memory = needle.len() - self.period; + } + continue 'search; + } + } + + // We have found a match! + let match_pos = self.position; + + // Note: add self.period instead of needle.len() to have overlapping matches + self.position += needle.len(); + if !long_period { + self.memory = 0; // set to needle.len() - self.period for overlapping matches + } + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Follows the ideas in `next()`. + // + // All the definitions are completely symmetrical, with period(x) = period(reverse(x)) + // and local_period(u, v) = local_period(reverse(v), reverse(u)), so if (u, v) + // is a critical factorization, so is (reverse(v), reverse(u)). Similarly, + // the "period" stored in self.period is the real period if long_period is + // false, and so is still valid for a reversed needle, and if long_period is + // true, all the algorithm requires is that self.period is less than or + // equal to the real period, which must be true for the forward case anyway. + // + // To search in reverse through the haystack, we search forward through + // a reversed haystack with a reversed needle, and the above paragraph shows + // that the precomputed parameters can be left alone. + #[inline] + fn next_back(&mut self, haystack: &[u8], needle: &[u8]) + -> S::Output + where S: TwoWayStrategy + { + // `next_back()` uses `self.end` as its cursor -- so that `next()` and `next_back()` + // are independent. + let old_end = self.end; + 'search: loop { + // Check that we have room to search in + if needle.len() > self.end { + self.end = 0; + return S::rejecting(0, old_end); + } + + if S::use_early_reject() && old_end != self.end { + return S::rejecting(self.end, old_end); + } + + // Quickly skip by large portions unrelated to our substring + if !self.byteset_contains(haystack[self.end - needle.len()]) { + self.end -= needle.len(); + continue 'search; + } + + // See if the left part of the needle matches + for i in (0..self.crit_pos).rev() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.crit_pos - i; + continue 'search; + } + } + + // See if the right part of the needle matches + for i in self.crit_pos..needle.len() { + if needle[i] != haystack[self.end - needle.len() + i] { + self.end -= self.period; + continue 'search; + } + } + + // We have found a match! + let match_pos = self.end - needle.len(); + // Note: sub self.period instead of needle.len() to have overlapping matches + self.end -= needle.len(); + + return S::matching(match_pos, match_pos + needle.len()); + } + } + + // Computes a critical factorization (u, v) of `arr`. + // Specifically, returns (i, p), where i is the starting index of v in some + // critical factorization (u, v) and p = period(v) + #[inline] + fn maximal_suffix(arr: &[u8], reversed: bool) -> (usize, usize) { + let mut left: usize = !0; // Corresponds to i in the paper + let mut right = 0; // Corresponds to j in the paper + let mut offset = 1; // Corresponds to k in the paper + let mut period = 1; // Corresponds to p in the paper + + while right + offset < arr.len() { + let a; + let b; + if reversed { + a = arr[left.wrapping_add(offset)]; + b = arr[right + offset]; + } else { + a = arr[right + offset]; + b = arr[left.wrapping_add(offset)]; + } + if a < b { + // Suffix is smaller, period is entire prefix so far. + right += offset; + offset = 1; + period = right.wrapping_sub(left); + } else if a == b { + // Advance through repetition of the current period. + if offset == period { + right += offset; + offset = 1; + } else { + offset += 1; + } + } else { + // Suffix is larger, start over from current location. + left = right; + right += 1; + offset = 1; + period = 1; + } + } + (left.wrapping_add(1), period) + } +} + +// TwoWayStrategy allows the algorithm to either skip non-matches as quickly +// as possible, or to work in a mode where it emits Rejects relatively quickly. +trait TwoWayStrategy { + type Output; + fn use_early_reject() -> bool; + fn rejecting(usize, usize) -> Self::Output; + fn matching(usize, usize) -> Self::Output; +} + +/// Skip to match intervals as quickly as possible +enum MatchOnly { } + +impl TwoWayStrategy for MatchOnly { + type Output = Option<(usize, usize)>; + + #[inline] + fn use_early_reject() -> bool { false } + #[inline] + fn rejecting(_a: usize, _b: usize) -> Self::Output { None } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { Some((a, b)) } +} + +/// Emit Rejects regularly +enum RejectAndMatch { } + +impl TwoWayStrategy for RejectAndMatch { + type Output = SearchStep; + + #[inline] + fn use_early_reject() -> bool { true } + #[inline] + fn rejecting(a: usize, b: usize) -> Self::Output { SearchStep::Reject(a, b) } + #[inline] + fn matching(a: usize, b: usize) -> Self::Output { SearchStep::Match(a, b) } +} diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index ba6a7c4a5f..6c5ff22232 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Operations on tuples +//! A finite heterogeneous sequence, `(T, U, ..)` //! //! To access a single element of a tuple one can use the `.0` //! field access syntax. @@ -28,7 +28,6 @@ //! * `Default` #![stable(feature = "rust1", since = "1.0.0")] -#![doc(primitive = "tuple")] use clone::Clone; use cmp::*; diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index 1506982586..35f8372a70 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -102,29 +102,6 @@ fn test_to_uppercase() { assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']); } -#[test] -fn test_to_titlecase() { - fn title(c: char) -> Vec { - c.to_titlecase().collect() - } - assert_eq!(title('a'), ['A']); - assert_eq!(title('ö'), ['Ö']); - assert_eq!(title('ß'), ['S', 's']); // not ẞ: Latin capital letter sharp s - assert_eq!(title('ü'), ['Ü']); - assert_eq!(title('💩'), ['💩']); - - assert_eq!(title('σ'), ['Σ']); - assert_eq!(title('τ'), ['Τ']); - assert_eq!(title('ι'), ['Ι']); - assert_eq!(title('γ'), ['Γ']); - assert_eq!(title('μ'), ['Μ']); - assert_eq!(title('α'), ['Α']); - assert_eq!(title('ς'), ['Σ']); - assert_eq!(title('DŽ'), ['Dž']); - assert_eq!(title('fi'), ['F', 'i']); - assert_eq!(title('ᾀ'), ['ᾈ']); -} - #[test] fn test_is_control() { assert!('\u{0}'.is_control()); diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index cab2175f89..247c3dcb9c 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -7,8 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unsigned_negation)] - use core::fmt::radix; #[test] diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 5c11f0196a..697c3ee254 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod sip; + use std::mem; use std::hash::{Hash, Hasher}; use std::default::Default; diff --git a/src/libcoretest/hash/sip.rs b/src/libcoretest/hash/sip.rs index 8289d06d04..9b6cedd25b 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcoretest/hash/sip.rs @@ -7,29 +7,62 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use test::Bencher; -use std::prelude::*; -use std::fmt; +use test::{Bencher, black_box}; -use str::Str; -use string::String; -use slice::{AsSlice, SlicePrelude}; -use vec::Vec; - -use core::hash::{Hash, Writer}; -use core::hash::sip::{SipState, hash, hash_with_keys}; +use core::hash::{Hash, Hasher}; +use core::hash::SipHasher; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); -impl<'a, S: Writer> Hash for Bytes<'a> { +impl<'a> Hash for Bytes<'a> { #[allow(unused_must_use)] - fn hash(&self, state: &mut S) { + fn hash(&self, state: &mut H) { let Bytes(v) = *self; state.write(v); } } +macro_rules! u8to64_le { + ($buf:expr, $i:expr) => + ($buf[0+$i] as u64 | + ($buf[1+$i] as u64) << 8 | + ($buf[2+$i] as u64) << 16 | + ($buf[3+$i] as u64) << 24 | + ($buf[4+$i] as u64) << 32 | + ($buf[5+$i] as u64) << 40 | + ($buf[6+$i] as u64) << 48 | + ($buf[7+$i] as u64) << 56); + ($buf:expr, $i:expr, $len:expr) => + ({ + let mut t = 0; + let mut out = 0; + while t < $len { + out |= ($buf[t+$i] as u64) << t*8; + t += 1; + } + out + }); +} + +fn hash(x: &T) -> u64 { + let mut st = SipHasher::new(); + x.hash(&mut st); + st.finish() +} + +fn hash_with_keys(k1: u64, k2: u64, x: &T) -> u64 { + let mut st = SipHasher::new_with_keys(k1, k2); + x.hash(&mut st); + st.finish() +} + +fn hash_bytes(x: &[u8]) -> u64 { + let mut s = SipHasher::default(); + Hasher::write(&mut s, x); + s.finish() +} + #[test] #[allow(unused_must_use)] fn test_siphash() { @@ -104,79 +137,43 @@ fn test_siphash() { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; let mut buf = Vec::new(); let mut t = 0; - let mut state_inc = SipState::new_with_keys(k0, k1); - let mut state_full = SipState::new_with_keys(k0, k1); - - fn to_hex_str(r: &[u8; 8]) -> String { - let mut s = String::new(); - for b in r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } - - fn result_bytes(h: u64) -> Vec { - vec![(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(h: u64) -> String { - let r = result_bytes(h); - let mut s = String::new(); - for b in &r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } + let mut state_inc = SipHasher::new_with_keys(k0, k1); while t < 64 { - debug!("siphash test {}: {}", t, buf); let vec = u8to64_le!(vecs[t], 0); - let out = hash_with_keys(k0, k1, &Bytes(buf)); - debug!("got {}, expected {}", out, vec); + let out = hash_with_keys(k0, k1, &Bytes(&buf)); assert_eq!(vec, out); - state_full.reset(); - state_full.write(buf); - let f = result_str(state_full.result()); - let i = result_str(state_inc.result()); - let v = to_hex_str(&vecs[t]); - debug!("{}: ({}) => inc={} full={}", t, v, i, f); + let full = hash_with_keys(k0, k1, &Bytes(&buf)); + let i = state_inc.finish(); - assert_eq!(f, i); - assert_eq!(f, v); + assert_eq!(full, i); + assert_eq!(full, vec); buf.push(t as u8); - state_inc.write(&[t as u8]); + Hasher::write(&mut state_inc, &[t as u8]); t += 1; } } #[test] #[cfg(target_arch = "arm")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86_64")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); + assert_eq!(hash(&(val as u64)), hash(&(val as usize))); + assert!(hash(&(val as u32)) != hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] @@ -200,7 +197,7 @@ fn test_hash_no_bytes_dropped_64() { assert!(hash(&val) != hash(&zero_byte(val, 6))); assert!(hash(&val) != hash(&zero_byte(val, 7))); - fn zero_byte(val: u64, byte: uint) -> u64 { + fn zero_byte(val: u64, byte: usize) -> u64 { assert!(byte < 8); val & !(0xff << (byte * 8)) } @@ -215,7 +212,7 @@ fn test_hash_no_bytes_dropped_32() { assert!(hash(&val) != hash(&zero_byte(val, 2))); assert!(hash(&val) != hash(&zero_byte(val, 3))); - fn zero_byte(val: u32, byte: uint) -> u32 { + fn zero_byte(val: u32, byte: usize) -> u32 { assert!(byte < 4); val & !(0xff << (byte * 8)) } @@ -230,8 +227,9 @@ fn test_hash_no_concat_alias() { assert!(s != t && t != u); assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - let v: (&[u8], &[u8], &[u8]) = (&[1], &[0, 0], &[0]); - let w: (&[u8], &[u8], &[u8]) = (&[1, 0, 0, 0], &[], &[]); + let u = [1, 0, 0, 0]; + let v = (&u[..1], &u[1..3], &u[3..]); + let w = (&u[..], &u[4..4], &u[4..4]); assert!(v != w); assert!(hash(&v) != hash(&w)); @@ -274,10 +272,88 @@ officia deserunt mollit anim id est laborum."; }) } +#[bench] +fn bench_u32(b: &mut Bencher) { + let u = 162629500u32; + let u = black_box(u); + b.iter(|| { + hash(&u) + }); + b.bytes = 8; +} + +#[bench] +fn bench_u32_keyed(b: &mut Bencher) { + let u = 162629500u32; + let u = black_box(u); + let k1 = black_box(0x1); + let k2 = black_box(0x2); + b.iter(|| { + hash_with_keys(k1, k2, &u) + }); + b.bytes = 8; +} + #[bench] fn bench_u64(b: &mut Bencher) { let u = 16262950014981195938u64; + let u = black_box(u); b.iter(|| { - assert_eq!(hash(&u), 5254097107239593357); - }) + hash(&u) + }); + b.bytes = 8; +} + +#[bench] +fn bench_bytes_4(b: &mut Bencher) { + let data = black_box([b' '; 4]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 4; +} + +#[bench] +fn bench_bytes_7(b: &mut Bencher) { + let data = black_box([b' '; 7]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 7; +} + +#[bench] +fn bench_bytes_8(b: &mut Bencher) { + let data = black_box([b' '; 8]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 8; +} + +#[bench] +fn bench_bytes_a_16(b: &mut Bencher) { + let data = black_box([b' '; 16]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 16; +} + +#[bench] +fn bench_bytes_b_32(b: &mut Bencher) { + let data = black_box([b' '; 32]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 32; +} + +#[bench] +fn bench_bytes_c_128(b: &mut Bencher) { + let data = black_box([b' '; 128]); + b.iter(|| { + hash_bytes(&data) + }); + b.bytes = 128; } diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 998f4b21ec..a9baa2cc47 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -117,7 +117,14 @@ mod tests { } #[test] - fn test_int_from_minus_sign() { - assert_eq!("-".parse::().ok(), None); + fn test_invalid() { + assert_eq!("--129".parse::().ok(), None); + assert_eq!("Съешь".parse::().ok(), None); + } + + #[test] + fn test_empty() { + assert_eq!("-".parse::().ok(), None); + assert_eq!("".parse::().ok(), None); } } diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index 8f1017c50a..865b049aae 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -10,7 +10,6 @@ use core::ptr::*; use core::mem; -use std::iter::repeat; #[test] fn test() { @@ -110,7 +109,7 @@ fn test_as_mut() { #[test] fn test_ptr_addition() { unsafe { - let xs = repeat(5).take(16).collect::>(); + let xs = vec![5; 16]; let mut ptr = xs.as_ptr(); let end = ptr.offset(16); @@ -128,7 +127,7 @@ fn test_ptr_addition() { m_ptr = m_ptr.offset(1); } - assert!(xs_mut == repeat(10).take(16).collect::>()); + assert!(xs_mut == vec![10; 16]); } } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index c2b28bd134..7ca89cfd0c 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { } Some(..) | None => { return &self.input[..0]; } }; - let mut end; + let end; loop { match self.cur.clone().next() { Some((_, c)) if c.is_xid_continue() => { diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 0d15f584d6..8953375297 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -56,7 +56,7 @@ //! optopt("o", "", "set output file name", "NAME"), //! optflag("h", "help", "print this help menu") //! ]; -//! let matches = match getopts(args.tail(), opts) { +//! let matches = match getopts(args[1..], opts) { //! Ok(m) => { m } //! Err(f) => { panic!(f.to_string()) } //! }; @@ -784,13 +784,13 @@ pub fn usage(brief: &str, opts: &[OptGroup]) -> String { // FIXME: #5516 should be graphemes not codepoints // wrapped description - row.push_str(&desc_rows.connect(&desc_sep[..])); + row.push_str(&desc_rows.join(&desc_sep[..])); row }); format!("{}\n\nOptions:\n{}\n", brief, - rows.collect::>().connect("\n")) + rows.collect::>().join("\n")) } fn format_option(opt: &OptGroup) -> String { @@ -836,7 +836,7 @@ pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { line.push_str(&opts.iter() .map(format_option) .collect::>() - .connect(" ")[..]); + .join(" ")[..]); line } diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index f8d80035d9..69120b5818 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -47,7 +47,8 @@ //! which is cyclic. //! //! ```rust -//! # #![feature(rustc_private, core, into_cow)] +//! #![feature(rustc_private, core, into_cow)] +//! //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; @@ -149,7 +150,8 @@ //! entity `&sube`). //! //! ```rust -//! # #![feature(rustc_private, core, into_cow)] +//! #![feature(rustc_private, core, into_cow)] +//! //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; @@ -207,7 +209,8 @@ //! Hasse-diagram for the subsets of the set `{x, y}`. //! //! ```rust -//! # #![feature(rustc_private, core, into_cow)] +//! #![feature(rustc_private, core, into_cow)] +//! //! use std::borrow::IntoCow; //! use std::io::Write; //! use graphviz as dot; @@ -312,6 +315,40 @@ pub enum LabelText<'a> { EscStr(Cow<'a, str>), } +/// The style for a node or edge. +/// See http://www.graphviz.org/doc/info/attrs.html#k:style for descriptions. +/// Note that some of these are not valid for edges. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Style { + None, + Solid, + Dashed, + Dotted, + Bold, + Rounded, + Diagonals, + Filled, + Striped, + Wedged, +} + +impl Style { + pub fn as_slice(self) -> &'static str { + match self { + Style::None => "", + Style::Solid => "solid", + Style::Dashed => "dashed", + Style::Dotted => "dotted", + Style::Bold => "bold", + Style::Rounded => "rounded", + Style::Diagonals => "diagonals", + Style::Filled => "filled", + Style::Striped => "striped", + Style::Wedged => "wedged", + } + } +} + // There is a tension in the design of the labelling API. // // For example, I considered making a `Labeller` trait that @@ -430,6 +467,16 @@ pub trait Labeller<'a,N,E> { let _ignored = e; LabelStr("".into_cow()) } + + /// Maps `n` to a style that will be used in the rendered output. + fn node_style(&'a self, _n: &N) -> Style { + Style::None + } + + /// Maps `e` to a style that will be used in the rendered output. + fn edge_style(&'a self, _e: &E) -> Style { + Style::None + } } impl<'a> LabelText<'a> { @@ -529,6 +576,8 @@ pub trait GraphWalk<'a, N, E> { pub enum RenderOption { NoEdgeLabels, NoNodeLabels, + NoEdgeStyles, + NoNodeStyles, } /// Returns vec holding all the default render options. @@ -562,30 +611,53 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N for n in g.nodes().iter() { try!(indent(w)); let id = g.node_id(n); - if options.contains(&RenderOption::NoNodeLabels) { - try!(writeln(w, &[id.as_slice(), ";"])); - } else { - let escaped = g.node_label(n).escape(); - try!(writeln(w, &[id.as_slice(), - "[label=\"", &escaped, "\"];"])); + + let escaped = &g.node_label(n).escape(); + + let mut text = vec![id.as_slice()]; + + if !options.contains(&RenderOption::NoNodeLabels) { + text.push("[label=\""); + text.push(escaped); + text.push("\"]"); } + + let style = g.node_style(n); + if !options.contains(&RenderOption::NoNodeStyles) && style != Style::None { + text.push("[style=\""); + text.push(style.as_slice()); + text.push("\"]"); + } + + text.push(";"); + try!(writeln(w, &text)); } for e in g.edges().iter() { - let escaped_label = g.edge_label(e).escape(); + let escaped_label = &g.edge_label(e).escape(); try!(indent(w)); let source = g.source(e); let target = g.target(e); let source_id = g.node_id(&source); let target_id = g.node_id(&target); - if options.contains(&RenderOption::NoEdgeLabels) { - try!(writeln(w, &[source_id.as_slice(), - " -> ", target_id.as_slice(), ";"])); - } else { - try!(writeln(w, &[source_id.as_slice(), - " -> ", target_id.as_slice(), - "[label=\"", &escaped_label, "\"];"])); + + let mut text = vec![source_id.as_slice(), " -> ", target_id.as_slice()]; + + if !options.contains(&RenderOption::NoEdgeLabels) { + text.push("[label=\""); + text.push(escaped_label); + text.push("\"]"); + } + + let style = g.edge_style(e); + if !options.contains(&RenderOption::NoEdgeStyles) && style != Style::None { + text.push("[style=\""); + text.push(style.as_slice()); + text.push("\"]"); } + + text.push(";"); + try!(writeln(w, &text)); } writeln(w, &["}"]) @@ -594,21 +666,23 @@ pub fn render_opts<'a, N:Clone+'a, E:Clone+'a, G:Labeller<'a,N,E>+GraphWalk<'a,N #[cfg(test)] mod tests { use self::NodeLabels::*; - use super::{Id, Labeller, Nodes, Edges, GraphWalk, render}; + use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style}; use super::LabelText::{self, LabelStr, EscStr}; use std::io; use std::io::prelude::*; use std::borrow::IntoCow; - use std::iter::repeat; /// each node is an index in a vector in the graph. type Node = usize; struct Edge { - from: usize, to: usize, label: &'static str + from: usize, + to: usize, + label: &'static str, + style: Style, } - fn edge(from: usize, to: usize, label: &'static str) -> Edge { - Edge { from: from, to: to, label: label } + fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge { + Edge { from: from, to: to, label: label, style: style } } struct LabelledGraph { @@ -624,6 +698,8 @@ mod tests { /// text. node_labels: Vec>, + node_styles: Vec