From 9346a6ac1cf9668de1386d5cad0a641871f935fd Mon Sep 17 00:00:00 2001 From: Angus Lees Date: Tue, 5 May 2015 17:26:13 +1000 Subject: [PATCH] Imported Upstream version 1.0.0~beta.3 --- AUTHORS.txt | 96 +- Makefile.in | 7 + configure | 98 +- mk/crates.mk | 35 +- mk/docs.mk | 10 +- mk/install.mk | 10 +- mk/main.mk | 15 +- mk/rt.mk | 4 + mk/tests.mk | 23 +- mk/util.mk | 3 + src/compiletest/common.rs | 11 +- src/compiletest/compiletest.rs | 22 +- src/compiletest/raise_fd_limit.rs | 79 + src/compiletest/runtest.rs | 153 +- src/doc/complement-design-faq.md | 21 +- src/doc/complement-lang-faq.md | 5 +- src/doc/index.md | 20 +- src/doc/intro.md | 589 +-- src/doc/reference.md | 2 +- src/doc/style/testing/unit.md | 8 +- src/doc/trpl/README.md | 203 +- src/doc/trpl/SUMMARY.md | 75 +- src/doc/trpl/academic-research.md | 46 + src/doc/trpl/advanced-macros.md | 242 - src/doc/trpl/advanced.md | 8 - src/doc/trpl/arrays-vectors-and-slices.md | 102 - src/doc/trpl/associated-types.md | 2 +- src/doc/trpl/attributes.md | 3 + src/doc/trpl/basic.md | 7 - src/doc/trpl/benchmark-tests.md | 2 +- src/doc/trpl/casting-between-types.md | 3 + src/doc/trpl/closures.md | 11 +- src/doc/trpl/comments.md | 38 +- .../trpl/{plugins.md => compiler-plugins.md} | 0 src/doc/trpl/compound-data-types.md | 364 -- src/doc/trpl/conclusion.md | 11 - src/doc/trpl/concurrency.md | 79 +- src/doc/trpl/conditional-compilation.md | 3 + src/doc/trpl/const.md | 3 + src/doc/trpl/crates-and-modules.md | 56 +- src/doc/trpl/debug-and-display.md | 3 + src/doc/trpl/deref-coercions.md | 3 + src/doc/trpl/drop.md | 3 + src/doc/trpl/effective-rust.md | 8 + src/doc/trpl/enums.md | 147 + src/doc/trpl/error-handling.md | 2 +- src/doc/trpl/ffi.md | 2 +- src/doc/trpl/for-loops.md | 43 + src/doc/trpl/functions.md | 136 +- src/doc/trpl/getting-started.md | 5 + src/doc/trpl/hello-cargo.md | 128 +- src/doc/trpl/hello-world.md | 146 +- src/doc/trpl/if-let.md | 3 + src/doc/trpl/if.md | 106 +- src/doc/trpl/installing-rust.md | 68 +- src/doc/trpl/intermediate.md | 7 - src/doc/trpl/iterators.md | 2 +- src/doc/trpl/learn-rust.md | 4 + src/doc/trpl/lifetimes.md | 3 + src/doc/trpl/looping.md | 133 - src/doc/trpl/macros.md | 239 +- src/doc/trpl/match.md | 140 +- src/doc/trpl/method-syntax.md | 10 +- src/doc/trpl/more-strings.md | 325 -- src/doc/trpl/move-semantics.md | 3 + src/doc/trpl/mutability.md | 3 + src/doc/trpl/nightly-rust.md | 102 + src/doc/trpl/no-stdlib.md | 2 +- src/doc/trpl/operators-and-overloading.md | 3 + src/doc/trpl/patterns.md | 98 +- src/doc/trpl/pointers.md | 699 --- src/doc/trpl/primitive-types.md | 268 ++ src/doc/trpl/references-and-borrowing.md | 3 + src/doc/trpl/slice-patterns.md | 18 + src/doc/trpl/static.md | 3 + src/doc/trpl/structs.md | 89 + src/doc/trpl/syntax-and-semantics.md | 10 + src/doc/trpl/testing.md | 2 +- src/doc/trpl/the-stack-and-the-heap.md | 3 + src/doc/trpl/tracing-macros.md | 91 - ...d-dynamic-dispatch.md => trait-objects.md} | 2 +- src/doc/trpl/traits.md | 82 +- src/doc/trpl/tuple-structs.md | 56 + src/doc/trpl/type-aliases.md | 3 + src/doc/trpl/ufcs.md | 3 + src/doc/trpl/{unsafe.md => unsafe-code.md} | 2 +- src/doc/trpl/unsized-types.md | 3 + src/doc/trpl/unstable.md | 1 - src/doc/trpl/variable-bindings.md | 106 +- src/doc/trpl/vectors.md | 32 + src/doc/trpl/while-loops.md | 93 + src/etc/gdb_rust_pretty_printing.py | 12 +- src/etc/htmldocck.py | 3 +- src/etc/lldb_rust_formatters.py | 28 +- src/etc/rustup.sh | 615 --- src/etc/snapshot.pyc | Bin 10095 -> 10095 bytes src/etc/unicode.py | 129 +- src/jemalloc/VERSION | 2 +- src/liballoc/arc.rs | 56 +- src/liballoc/boxed.rs | 32 +- src/liballoc/rc.rs | 10 +- src/libarena/lib.rs | 9 +- src/libbacktrace/ChangeLog | 53 + src/libbacktrace/ChangeLog.jit | 14 + src/libbacktrace/Makefile.am | 12 +- src/libbacktrace/Makefile.in | 35 +- src/libbacktrace/alloc.c | 8 +- src/libbacktrace/atomic.c | 8 +- src/libbacktrace/backtrace-supported.h.in | 8 +- src/libbacktrace/backtrace.c | 8 +- src/libbacktrace/backtrace.h | 8 +- src/libbacktrace/btest.c | 10 +- src/libbacktrace/configure | 138 +- src/libbacktrace/configure.ac | 13 +- src/libbacktrace/dwarf.c | 33 +- src/libbacktrace/elf.c | 12 +- src/libbacktrace/fileline.c | 8 +- src/libbacktrace/internal.h | 15 +- src/libbacktrace/mmap.c | 36 +- src/libbacktrace/mmapio.c | 8 +- src/libbacktrace/nounwind.c | 8 +- src/libbacktrace/posix.c | 8 +- src/libbacktrace/print.c | 8 +- src/libbacktrace/read.c | 8 +- src/libbacktrace/simple.c | 8 +- src/libbacktrace/sort.c | 108 + src/libbacktrace/state.c | 8 +- src/libbacktrace/stest.c | 137 + src/libbacktrace/unknown.c | 8 +- src/libcollections/binary_heap.rs | 44 +- src/libcollections/bit.rs | 42 +- src/libcollections/borrow.rs | 20 +- src/libcollections/btree/map.rs | 71 +- src/libcollections/btree/node.rs | 7 +- src/libcollections/btree/set.rs | 46 +- src/libcollections/enum_set.rs | 4 +- src/libcollections/fmt.rs | 77 +- src/libcollections/lib.rs | 2 + src/libcollections/linked_list.rs | 20 +- src/libcollections/slice.rs | 11 +- src/libcollections/str.rs | 499 +- src/libcollections/string.rs | 74 +- src/libcollections/vec.rs | 109 +- src/libcollections/vec_deque.rs | 26 +- src/libcollections/vec_map.rs | 74 +- src/libcollectionstest/bench.rs | 10 +- src/libcollectionstest/bit/set.rs | 9 +- src/libcollectionstest/bit/vec.rs | 87 +- src/libcollectionstest/btree/map.rs | 4 +- src/libcollectionstest/slice.rs | 20 +- src/libcollectionstest/str.rs | 504 +- src/libcollectionstest/string.rs | 1 - src/libcore/any.rs | 17 +- src/libcore/atomic.rs | 20 + src/libcore/cell.rs | 10 +- src/libcore/char.rs | 5 +- src/libcore/clone.rs | 32 +- src/libcore/cmp.rs | 21 - src/libcore/convert.rs | 64 +- src/libcore/default.rs | 9 - src/libcore/fmt/float.rs | 147 +- src/libcore/fmt/mod.rs | 109 +- src/libcore/fmt/num.rs | 43 +- src/libcore/fmt/rt/v1.rs | 47 +- src/libcore/hash/mod.rs | 3 +- src/libcore/hash/sip.rs | 1 - src/libcore/intrinsics.rs | 24 +- src/libcore/iter.rs | 650 +-- src/libcore/lib.rs | 4 +- src/libcore/macros.rs | 3 +- src/libcore/marker.rs | 187 +- src/libcore/mem.rs | 8 +- src/libcore/nonzero.rs | 12 +- src/libcore/num/f32.rs | 85 +- src/libcore/num/f64.rs | 85 +- src/libcore/num/float_macros.rs | 142 + src/libcore/num/int_macros.rs | 4 +- src/libcore/num/mod.rs | 1896 +------- src/libcore/num/uint_macros.rs | 4 +- src/libcore/num/wrapping.rs | 31 - src/libcore/ops.rs | 8 +- src/libcore/option.rs | 51 +- src/libcore/panicking.rs | 6 +- src/libcore/prelude.rs | 5 +- src/libcore/ptr.rs | 21 +- src/libcore/raw.rs | 4 +- src/libcore/result.rs | 225 +- src/libcore/slice.rs | 52 +- src/libcore/str/mod.rs | 803 ++-- src/libcore/str/pattern.rs | 229 +- src/libcoretest/cmp.rs | 2 - src/libcoretest/fmt/float.rs | 17 + src/libcoretest/fmt/num.rs | 28 +- src/libcoretest/iter.rs | 54 +- src/libcoretest/lib.rs | 6 +- src/libcoretest/num/int_macros.rs | 73 +- src/libcoretest/num/mod.rs | 31 +- src/libcoretest/num/uint_macros.rs | 33 +- src/libcoretest/str.rs | 376 +- src/libflate/lib.rs | 5 +- src/libfmt_macros/lib.rs | 4 +- src/libgetopts/lib.rs | 2 +- src/liblibc/lib.rs | 52 +- src/liblog/directive.rs | 2 +- src/librand/chacha.rs | 2 - src/librand/distributions/exponential.rs | 12 - src/librand/distributions/gamma.rs | 48 - src/librand/distributions/mod.rs | 20 +- src/librand/distributions/normal.rs | 26 - src/librand/distributions/range.rs | 28 +- src/librand/lib.rs | 159 +- src/librand/rand_impls.rs | 52 - src/librand/reseeding.rs | 30 - src/librbml/lib.rs | 51 +- src/librustc/diagnostics.rs | 243 +- src/librustc/lib.rs | 4 + src/librustc/macros.rs | 46 + src/librustc/metadata/common.rs | 64 +- src/librustc/metadata/creader.rs | 7 +- src/librustc/metadata/cstore.rs | 12 +- src/librustc/metadata/decoder.rs | 13 +- src/librustc/metadata/encoder.rs | 31 +- src/librustc/metadata/loader.rs | 16 +- src/librustc/metadata/tydecode.rs | 24 +- src/librustc/metadata/tyencode.rs | 14 +- src/librustc/middle/astencode.rs | 293 +- src/librustc/middle/check_const.rs | 14 +- src/librustc/middle/check_match.rs | 12 +- src/librustc/middle/const_eval.rs | 2 +- src/librustc/middle/dataflow.rs | 88 +- src/librustc/middle/dead.rs | 29 +- src/librustc/middle/def.rs | 12 +- src/librustc/middle/effect.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 147 +- src/librustc/middle/infer/error_reporting.rs | 11 +- src/librustc/middle/infer/mod.rs | 2 +- .../middle/infer/region_inference/graphviz.rs | 2 +- .../middle/infer/region_inference/mod.rs | 2 +- src/librustc/middle/lang_items.rs | 13 +- src/librustc/middle/liveness.rs | 26 +- src/librustc/middle/mem_categorization.rs | 62 +- src/librustc/middle/region.rs | 50 +- src/librustc/middle/resolve_lifetime.rs | 225 +- src/librustc/middle/stability.rs | 67 +- src/librustc/middle/subst.rs | 17 +- src/librustc/middle/traits/coherence.rs | 42 +- src/librustc/middle/traits/fulfill.rs | 2 +- src/librustc/middle/traits/object_safety.rs | 9 +- src/librustc/middle/traits/select.rs | 24 +- src/librustc/middle/traits/util.rs | 31 +- src/librustc/middle/ty.rs | 474 +- src/librustc/middle/ty_fold.rs | 31 +- src/librustc/middle/ty_relate/mod.rs | 38 +- src/librustc/plugin/mod.rs | 2 +- src/librustc/plugin/registry.rs | 14 + src/librustc/session/config.rs | 2 +- src/librustc/session/mod.rs | 15 +- src/librustc/util/num.rs | 98 + src/librustc/util/ppaux.rs | 27 +- src/librustc_back/fs.rs | 101 +- src/librustc_back/lib.rs | 5 +- src/librustc_back/rpath.rs | 3 +- src/librustc_back/sha2.rs | 11 +- src/librustc_back/tempdir.rs | 4 +- src/librustc_borrowck/borrowck/check_loans.rs | 1 + src/librustc_borrowck/borrowck/fragments.rs | 6 +- src/librustc_borrowck/borrowck/mod.rs | 67 +- src/librustc_borrowck/borrowck/move_data.rs | 19 +- .../diagnostics.rs} | 8 +- src/librustc_borrowck/lib.rs | 4 + src/librustc_driver/driver.rs | 13 +- src/librustc_driver/lib.rs | 5 +- src/librustc_driver/pretty.rs | 2 +- src/librustc_driver/test.rs | 7 +- src/librustc_lint/builtin.rs | 20 +- src/librustc_llvm/lib.rs | 5 +- src/librustc_privacy/lib.rs | 24 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/lib.rs | 181 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/librustc_trans/back/link.rs | 4 +- src/librustc_trans/back/lto.rs | 23 +- src/librustc_trans/back/write.rs | 15 + src/librustc_trans/save/mod.rs | 18 +- src/librustc_trans/trans/_match.rs | 34 +- src/librustc_trans/trans/adt.rs | 6 +- src/librustc_trans/trans/attributes.rs | 281 ++ src/librustc_trans/trans/base.rs | 688 +-- src/librustc_trans/trans/cabi_aarch64.rs | 84 + src/librustc_trans/trans/cabi_x86_64.rs | 4 +- src/librustc_trans/trans/callee.rs | 15 +- src/librustc_trans/trans/cleanup.rs | 7 +- src/librustc_trans/trans/closure.rs | 15 +- src/librustc_trans/trans/common.rs | 40 +- src/librustc_trans/trans/consts.rs | 150 +- src/librustc_trans/trans/context.rs | 22 +- src/librustc_trans/trans/controlflow.rs | 17 +- src/librustc_trans/trans/debuginfo.rs | 121 +- src/librustc_trans/trans/declare.rs | 261 + src/librustc_trans/trans/expr.rs | 348 +- src/librustc_trans/trans/foreign.rs | 64 +- src/librustc_trans/trans/glue.rs | 54 +- src/librustc_trans/trans/intrinsic.rs | 12 + src/librustc_trans/trans/meth.rs | 14 +- src/librustc_trans/trans/mod.rs | 54 +- src/librustc_trans/trans/monomorphize.rs | 16 +- src/librustc_trans/trans/tvec.rs | 2 +- src/librustc_trans/trans/type_of.rs | 8 +- src/librustc_typeck/astconv.rs | 373 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/callee.rs | 42 +- src/librustc_typeck/check/cast.rs | 190 + src/librustc_typeck/check/coercion.rs | 390 +- src/librustc_typeck/check/method/confirm.rs | 136 +- src/librustc_typeck/check/method/mod.rs | 32 +- src/librustc_typeck/check/method/probe.rs | 167 +- src/librustc_typeck/check/method/suggest.rs | 4 +- src/librustc_typeck/check/mod.rs | 479 +- src/librustc_typeck/check/op.rs | 40 +- src/librustc_typeck/check/regionck.rs | 31 +- src/librustc_typeck/check/vtable.rs | 39 - src/librustc_typeck/check/wf.rs | 59 +- src/librustc_typeck/check/writeback.rs | 13 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/coherence/overlap.rs | 42 +- src/librustc_typeck/collect.rs | 151 +- .../constrained_type_params.rs | 92 +- src/librustc_typeck/diagnostics.rs | 4 +- src/librustc_typeck/lib.rs | 2 +- src/librustc_typeck/variance.rs | 344 +- src/librustdoc/clean/inline.rs | 73 +- src/librustdoc/clean/mod.rs | 272 +- src/librustdoc/clean/simplify.rs | 180 + src/librustdoc/core.rs | 4 - src/librustdoc/doctree.rs | 2 + src/librustdoc/fold.rs | 9 +- src/librustdoc/html/format.rs | 180 +- src/librustdoc/html/layout.rs | 6 +- src/librustdoc/html/markdown.rs | 63 +- src/librustdoc/html/render.rs | 264 +- src/librustdoc/html/static/main.js | 20 +- src/librustdoc/lib.rs | 11 +- src/librustdoc/markdown.rs | 14 +- src/librustdoc/passes.rs | 8 +- src/librustdoc/test.rs | 86 +- src/librustdoc/visit_ast.rs | 21 +- src/libserialize/json.rs | 36 +- src/libserialize/lib.rs | 3 +- src/libserialize/serialize.rs | 32 - src/libstd/ascii.rs | 12 +- src/libstd/collections/hash/map.rs | 73 +- src/libstd/collections/hash/set.rs | 73 +- src/libstd/collections/hash/table.rs | 2 +- src/libstd/collections/mod.rs | 335 +- src/libstd/dynamic_lib.rs | 11 +- src/libstd/env.rs | 9 +- src/libstd/error.rs | 24 +- src/libstd/ffi/c_str.rs | 33 +- src/libstd/ffi/mod.rs | 8 - src/libstd/ffi/os_str.rs | 87 +- src/libstd/fs.rs | 376 +- src/libstd/io/buffered.rs | 133 +- src/libstd/io/cursor.rs | 8 +- src/libstd/io/error.rs | 20 +- src/libstd/io/mod.rs | 30 +- src/libstd/io/prelude.rs | 1 + src/libstd/io/stdio.rs | 56 +- src/libstd/lib.rs | 27 +- src/libstd/macros.rs | 50 +- src/libstd/net/addr.rs | 262 +- src/libstd/net/ip.rs | 294 +- src/libstd/net/mod.rs | 21 +- src/libstd/net/tcp.rs | 12 +- src/libstd/net/test.rs | 17 +- src/libstd/net/udp.rs | 5 +- src/libstd/num/f32.rs | 681 +-- src/libstd/num/f64.rs | 659 +-- src/libstd/num/mod.rs | 1658 +------ src/libstd/num/strconv.rs | 558 --- src/libstd/num/uint_macros.rs | 21 +- src/libstd/old_io/buffered.rs | 702 --- src/libstd/old_io/comm_adapters.rs | 247 - src/libstd/old_io/extensions.rs | 564 --- src/libstd/old_io/fs.rs | 1654 ------- src/libstd/old_io/mem.rs | 765 --- src/libstd/old_io/mod.rs | 1984 -------- src/libstd/old_io/net/addrinfo.rs | 137 - src/libstd/old_io/net/ip.rs | 710 --- src/libstd/old_io/net/mod.rs | 50 - src/libstd/old_io/net/pipe.rs | 883 ---- src/libstd/old_io/net/tcp.rs | 1483 ------ src/libstd/old_io/net/udp.rs | 459 -- src/libstd/old_io/pipe.rs | 141 - src/libstd/old_io/process.rs | 1239 ----- src/libstd/old_io/result.rs | 130 - src/libstd/old_io/stdio.rs | 540 --- src/libstd/old_io/tempfile.rs | 188 - src/libstd/old_io/test.rs | 177 - src/libstd/old_io/timer.rs | 488 -- src/libstd/old_io/util.rs | 495 -- src/libstd/old_path/mod.rs | 989 ---- src/libstd/old_path/posix.rs | 1348 ------ src/libstd/old_path/windows.rs | 2331 --------- src/libstd/panicking.rs | 2 +- src/libstd/path.rs | 85 +- src/libstd/prelude/v1.rs | 13 +- src/libstd/process.rs | 80 +- src/libstd/rand/mod.rs | 538 +-- src/libstd/rand/os.rs | 25 +- src/libstd/rand/reader.rs | 86 +- src/libstd/rt/unwind.rs | 28 +- src/libstd/sync/barrier.rs | 6 +- src/libstd/sync/condvar.rs | 36 +- src/libstd/sync/mod.rs | 13 +- src/libstd/sync/mpsc/mod.rs | 58 +- src/libstd/sync/mpsc/select.rs | 4 +- src/libstd/sync/mutex.rs | 8 +- src/libstd/sync/once.rs | 2 +- src/libstd/sync/rwlock.rs | 20 +- src/libstd/sys/common/backtrace.rs | 4 +- src/libstd/sys/common/condvar.rs | 10 +- src/libstd/sys/common/mod.rs | 93 +- src/libstd/sys/common/mutex.rs | 8 +- src/libstd/sys/common/net.rs | 971 ---- src/libstd/{sync => sys/common}/poison.rs | 2 +- src/libstd/sys/common/remutex.rs | 233 + src/libstd/sys/common/rwlock.rs | 14 +- src/libstd/sys/common/thread_local.rs | 2 +- src/libstd/sys/common/wtf8.rs | 58 +- src/libstd/sys/unix/c.rs | 48 +- src/libstd/sys/unix/condvar.rs | 7 +- src/libstd/sys/unix/ext.rs | 108 +- src/libstd/sys/unix/fd.rs | 25 +- src/libstd/sys/unix/fs.rs | 408 -- src/libstd/sys/unix/fs2.rs | 12 +- src/libstd/sys/unix/mod.rs | 135 +- src/libstd/sys/unix/mutex.rs | 48 + src/libstd/sys/unix/net.rs | 15 +- src/libstd/sys/unix/os.rs | 14 +- src/libstd/sys/unix/pipe.rs | 328 -- src/libstd/sys/unix/pipe2.rs | 15 +- src/libstd/sys/unix/process.rs | 627 --- src/libstd/sys/unix/process2.rs | 442 +- src/libstd/sys/unix/sync.rs | 29 +- src/libstd/sys/unix/tcp.rs | 164 - src/libstd/sys/unix/thread.rs | 2 +- src/libstd/sys/unix/timer.rs | 294 -- src/libstd/sys/unix/tty.rs | 81 - src/libstd/sys/windows/c.rs | 36 + src/libstd/sys/windows/ext.rs | 117 +- src/libstd/sys/windows/fs.rs | 452 -- src/libstd/sys/windows/fs2.rs | 50 +- src/libstd/sys/windows/handle.rs | 59 +- src/libstd/sys/windows/helper_signal.rs | 38 - src/libstd/sys/windows/mod.rs | 184 +- src/libstd/sys/windows/mutex.rs | 31 + src/libstd/sys/windows/net.rs | 27 +- src/libstd/sys/windows/os.rs | 34 +- src/libstd/sys/windows/pipe.rs | 775 --- src/libstd/sys/windows/pipe2.rs | 63 +- src/libstd/sys/windows/process.rs | 518 -- src/libstd/sys/windows/process2.rs | 55 +- src/libstd/sys/windows/sync.rs | 18 +- src/libstd/sys/windows/tcp.rs | 230 - src/libstd/sys/windows/timer.rs | 214 - src/libstd/sys/windows/tty.rs | 169 - src/libstd/thread/local.rs | 26 +- src/libstd/thread/mod.rs | 143 +- .../thread/{scoped.rs => scoped_tls.rs} | 10 +- src/libstd/time/duration.rs | 9 +- src/libstd/tuple.rs | 2 - src/libsyntax/ast.rs | 34 +- src/libsyntax/ast_map/blocks.rs | 29 +- src/libsyntax/ast_util.rs | 4 +- src/libsyntax/attr.rs | 21 +- src/libsyntax/codemap.rs | 134 +- src/libsyntax/diagnostic.rs | 221 +- src/libsyntax/ext/asm.rs | 34 +- src/libsyntax/ext/base.rs | 50 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/ext/cfg.rs | 2 +- src/libsyntax/ext/deriving/clone.rs | 2 +- src/libsyntax/ext/deriving/encodable.rs | 2 +- src/libsyntax/ext/deriving/generic/mod.rs | 96 +- src/libsyntax/ext/deriving/mod.rs | 3 - src/libsyntax/ext/deriving/rand.rs | 175 - src/libsyntax/ext/env.rs | 2 +- src/libsyntax/ext/expand.rs | 150 +- src/libsyntax/ext/format.rs | 60 +- src/libsyntax/ext/log_syntax.rs | 2 - src/libsyntax/ext/mtwt.rs | 2 +- src/libsyntax/ext/quote.rs | 6 +- src/libsyntax/ext/source_util.rs | 9 +- src/libsyntax/ext/tt/macro_parser.rs | 40 +- src/libsyntax/ext/tt/macro_rules.rs | 53 +- src/libsyntax/ext/tt/transcribe.rs | 14 +- src/libsyntax/feature_gate.rs | 14 +- src/libsyntax/fold.rs | 8 +- src/libsyntax/lib.rs | 16 +- src/libsyntax/parse/attr.rs | 30 +- src/libsyntax/parse/lexer/comments.rs | 4 +- src/libsyntax/parse/lexer/mod.rs | 12 +- src/libsyntax/parse/mod.rs | 27 +- src/libsyntax/parse/obsolete.rs | 2 +- src/libsyntax/parse/parser.rs | 2802 ++++++----- src/libsyntax/parse/token.rs | 16 - src/libsyntax/print/pp.rs | 2 +- src/libsyntax/print/pprust.rs | 14 +- src/libsyntax/ptr.rs | 7 + src/libsyntax/test.rs | 2 +- src/libsyntax/util/parser_testing.rs | 2 +- src/libsyntax/util/small_vector.rs | 14 + src/libsyntax/visit.rs | 14 +- src/libterm/terminfo/parm.rs | 18 +- src/libterm/terminfo/searcher.rs | 2 +- src/libtest/lib.rs | 11 +- src/libtest/stats.rs | 164 +- src/libunicode/lib.rs | 3 - src/libunicode/tables.rs | 4180 +++-------------- src/libunicode/u_str.rs | 17 +- .../utils/llvm-build/llvmbuild/__init__.pyc | Bin 261 -> 261 bytes .../llvm-build/llvmbuild/componentinfo.pyc | Bin 20261 -> 20261 bytes .../utils/llvm-build/llvmbuild/configutil.pyc | Bin 2075 -> 2075 bytes src/llvm/utils/llvm-build/llvmbuild/main.pyc | Bin 31108 -> 31108 bytes src/llvm/utils/llvm-build/llvmbuild/util.pyc | Bin 1644 -> 1644 bytes src/rust-installer/install-template.sh | 2 +- src/rustbook/book.rs | 3 +- src/rustbook/build.rs | 12 +- src/rustbook/javascript.rs | 2 + src/rustllvm/RustWrapper.cpp | 11 + src/test/auxiliary/coherence_copy_like_lib.rs | 4 +- src/test/auxiliary/coherence_orphan_lib.rs | 2 +- src/test/auxiliary/inline-default-methods.rs | 14 + src/test/auxiliary/internal_unstable.rs | 33 + src/test/auxiliary/issue-11224.rs | 2 +- .../lib.rs => auxiliary/issue-13698.rs} | 8 +- src/test/auxiliary/issue-15318.rs | 15 + src/test/auxiliary/issue-17476.rs | 16 + src/test/auxiliary/issue-20646.rs | 15 + src/test/auxiliary/issue-20727.rs | 38 + src/test/auxiliary/issue-21092.rs | 20 + src/test/auxiliary/issue-21801.rs | 17 + src/test/auxiliary/issue-22025.rs | 18 + .../issue-23207-1.rs} | 5 +- src/test/auxiliary/issue-23207-2.rs | 16 + src/test/auxiliary/issue_3907.rs | 6 +- src/test/auxiliary/lang-item-public.rs | 8 +- src/test/auxiliary/llvm_pass_plugin.rs | 28 + src/test/auxiliary/private_trait_xc.rs | 4 +- .../rustdoc-default-impl.rs} | 2 +- .../rustdoc-extern-default-method.rs} | 0 .../rustdoc-extern-method.rs} | 0 .../lib.rs => auxiliary/rustdoc-ffi.rs} | 0 src/test/auxiliary/svh-a-base.rs | 7 +- src/test/auxiliary/svh-a-change-lit.rs | 7 +- .../auxiliary/svh-a-change-significant-cfg.rs | 7 +- .../auxiliary/svh-a-change-trait-bound.rs | 7 +- src/test/auxiliary/svh-a-change-type-arg.rs | 7 +- src/test/auxiliary/svh-a-change-type-ret.rs | 7 +- .../auxiliary/svh-a-change-type-static.rs | 6 +- src/test/auxiliary/svh-a-comment.rs | 7 +- src/test/auxiliary/svh-a-doc.rs | 7 +- src/test/auxiliary/svh-a-macro.rs | 7 +- src/test/auxiliary/svh-a-no-change.rs | 7 +- src/test/auxiliary/svh-a-redundant-cfg.rs | 7 +- src/test/auxiliary/svh-a-whitespace.rs | 7 +- src/test/auxiliary/trait_impl_conflict.rs | 4 +- ...lt_trait_impl_cross_crate_coherence_lib.rs | 4 +- src/test/bench/core-map.rs | 6 +- src/test/bench/core-std.rs | 32 +- src/test/bench/noise.rs | 5 +- src/test/bench/shootout-binarytrees.rs | 7 +- src/test/bench/shootout-fannkuch-redux.rs | 4 +- src/test/bench/shootout-fasta-redux.rs | 40 +- src/test/bench/shootout-fasta.rs | 19 +- src/test/bench/shootout-k-nucleotide-pipes.rs | 29 +- src/test/bench/shootout-k-nucleotide.rs | 10 +- src/test/bench/shootout-mandelbrot.rs | 23 +- src/test/bench/shootout-nbody.rs | 21 +- src/test/bench/shootout-reverse-complement.rs | 65 +- src/test/bench/shootout-spectralnorm.rs | 5 +- src/test/bench/sudoku.rs | 1 - .../gated-macro-reexports.rs | 1 - ...pe-projection-from-multiple-supertraits.rs | 3 + ...ed-types-ICE-when-projecting-out-of-err.rs | 6 +- .../associated-types-eq-expr-path.rs | 2 +- .../associated-types-issue-17359.rs | 2 +- ...sociated-types-multiple-types-one-trait.rs | 2 +- ...sociated-types-no-suitable-supertrait-2.rs | 31 + ...associated-types-no-suitable-supertrait.rs | 16 +- .../associated-types-unconstrained.rs | 2 +- .../compile-fail/bad-mid-path-type-params.rs | 2 - src/test/compile-fail/bad-sized.rs | 4 +- .../borrowck-escaping-closure-error-1.rs | 25 + .../borrowck-escaping-closure-error-2.rs | 25 + ...orrowck-use-uninitialized-in-cast-trait.rs | 20 + .../borrowck-use-uninitialized-in-cast.rs | 20 + ...nket-conflicts-with-blanket-implemented.rs | 5 +- ...et-conflicts-with-blanket-unimplemented.rs | 4 +- ...herence-conflicting-negative-trait-impl.rs | 2 +- .../coherence-default-trait-impl.rs | 10 +- .../coherence-impl-trait-for-trait.rs | 32 + src/test/compile-fail/coherence-orphan.rs | 1 - .../coherence-overlap-all-t-and-tuple.rs | 28 + ...erence_copy_like_err_fundamental_struct.rs | 4 +- ...ce_copy_like_err_fundamental_struct_ref.rs | 4 +- ..._copy_like_err_fundamental_struct_tuple.rs | 4 +- .../coherence_copy_like_err_struct.rs | 4 +- .../coherence_copy_like_err_tuple.rs | 4 +- .../derive-no-std-not-supported.rs | 6 - src/test/compile-fail/dst-bad-coerce2.rs | 2 +- src/test/compile-fail/dst-bad-coercions.rs | 4 +- src/test/compile-fail/dupe-symbols-1.rs | 21 + src/test/compile-fail/dupe-symbols-2.rs | 25 + src/test/compile-fail/dupe-symbols-3.rs | 21 + src/test/compile-fail/dupe-symbols-4.rs | 31 + src/test/compile-fail/dupe-symbols-5.rs | 20 + src/test/compile-fail/dupe-symbols-6.rs | 18 + src/test/compile-fail/dupe-symbols-7.rs | 15 + src/test/compile-fail/enum-to-float-cast-2.rs | 28 + src/test/compile-fail/enum-to-float-cast.rs | 4 - src/test/compile-fail/fat-ptr-cast.rs | 19 + src/test/compile-fail/gated-box-patterns.rs | 1 - src/test/compile-fail/gated-box-syntax.rs | 1 - src/test/compile-fail/gated-link-args.rs | 1 - .../gated-link-llvm-intrinsics.rs | 1 - .../compile-fail/gated-plugin_registrar.rs | 1 - .../compile-fail/gated-unsafe-destructor.rs | 2 - .../impl-unused-rps-in-assoc-type.rs | 28 + src/test/compile-fail/implicit-method-bind.rs | 4 +- .../compile-fail/internal-unstable-noallow.rs | 6 + src/test/compile-fail/internal-unstable.rs | 2 + src/test/compile-fail/issue-13853-2.rs | 4 +- src/test/compile-fail/issue-13853.rs | 4 +- src/test/compile-fail/issue-14853.rs | 3 +- src/test/compile-fail/issue-16048.rs | 2 +- src/test/compile-fail/issue-16747.rs | 8 +- src/test/compile-fail/issue-18107.rs | 4 +- src/test/compile-fail/issue-18389.rs | 7 +- src/test/compile-fail/issue-18611.rs | 4 +- src/test/compile-fail/issue-18819.rs | 6 +- src/test/compile-fail/issue-19244-1.rs | 4 +- src/test/compile-fail/issue-19244-2.rs | 4 +- .../issue-19482.rs} | 7 +- src/test/compile-fail/issue-19660.rs | 6 +- src/test/compile-fail/issue-2063.rs | 9 +- src/test/compile-fail/issue-20772.rs | 15 + src/test/compile-fail/issue-20831-debruijn.rs | 3 +- src/test/compile-fail/issue-20939.rs | 16 + src/test/compile-fail/issue-21950.rs | 20 + src/test/compile-fail/issue-22034.rs | 19 + src/test/compile-fail/issue-22289.rs | 13 + src/test/compile-fail/issue-22370.rs | 18 + src/test/compile-fail/issue-22384.rs | 18 + src/test/compile-fail/issue-22560.rs | 21 + src/test/compile-fail/issue-22886.rs | 31 + src/test/compile-fail/issue-23080-2.rs | 4 +- ...e-23338-locals-die-before-temps-of-body.rs | 36 + src/test/compile-fail/issue-23729.rs | 43 + src/test/compile-fail/issue-23827.rs | 43 + src/test/compile-fail/issue-24036.rs | 30 + .../compile-fail/issue-24267-flow-exit.rs | 29 + src/test/compile-fail/issue-24356.rs | 40 + src/test/compile-fail/issue-24365.rs | 29 + src/test/compile-fail/issue-3702-2.rs | 7 +- src/test/compile-fail/issue-4335.rs | 2 +- src/test/compile-fail/issue-5035-2.rs | 4 +- src/test/compile-fail/issue-5883.rs | 6 +- src/test/compile-fail/issue-7575.rs | 8 +- src/test/compile-fail/issue-8767.rs | 2 - src/test/compile-fail/kindck-copy.rs | 3 +- .../compile-fail/kindck-impl-type-params-2.rs | 4 +- .../compile-fail/kindck-impl-type-params.rs | 2 +- src/test/compile-fail/kindck-send-object.rs | 4 +- src/test/compile-fail/kindck-send-object1.rs | 4 +- src/test/compile-fail/kindck-send-object2.rs | 4 +- src/test/compile-fail/lint-stability.rs | 1 - src/test/compile-fail/lint-type-limits.rs | 4 +- src/test/compile-fail/lint-unsafe-code.rs | 7 +- .../compile-fail/lint-uppercase-variables.rs | 2 - .../lint-visible-private-types.rs | 2 +- .../compile-fail/loop-labeled-break-value.rs | 2 +- .../loops-reject-duplicate-labels-2.rs | 51 + .../loops-reject-duplicate-labels.rs | 60 + ...loops-reject-labels-shadowing-lifetimes.rs | 120 + .../loops-reject-lifetime-shadowing-label.rs | 41 + .../macro-backtrace-invalid-internals.rs | 57 + .../compile-fail/macro-backtrace-nested.rs | 29 + .../compile-fail/macro-backtrace-println.rs | 29 + .../compile-fail/macro-incomplete-parse.rs | 9 +- .../non-constant-expr-for-fixed-len-vec.rs | 2 +- .../object-does-not-impl-trait.rs | 4 +- .../compile-fail/object-safety-no-static.rs | 2 +- .../compile-fail/object-safety-phantom-fn.rs | 6 +- .../old-suffixes-are-really-forbidden.rs | 14 + .../compile-fail/on-unimplemented-bad-anno.rs | 6 - src/test/compile-fail/on-unimplemented.rs | 3 - src/test/compile-fail/phantom-oibit.rs | 4 +- src/test/compile-fail/privacy-ns2.rs | 8 +- src/test/compile-fail/privacy1.rs | 8 +- src/test/compile-fail/privacy4.rs | 8 +- src/test/compile-fail/range-1.rs | 1 + .../region-object-lifetime-in-coercion.rs | 2 +- ...c-type-in-supertrait-outlives-container.rs | 4 +- ...ions-assoc-type-outlives-container-hrtb.rs | 4 +- ...egions-assoc-type-outlives-container-wc.rs | 4 +- .../regions-assoc-type-outlives-container.rs | 4 +- ...gions-close-associated-type-into-object.rs | 4 +- .../regions-close-object-into-object-1.rs | 6 +- .../regions-close-object-into-object-2.rs | 6 +- .../regions-close-object-into-object-3.rs | 8 +- .../regions-close-object-into-object-4.rs | 6 +- .../regions-close-over-borrowed-ref-in-obj.rs | 4 +- src/test/compile-fail/regions-nested-fns-2.rs | 2 +- src/test/compile-fail/required-lang-item.rs | 6 +- src/test/compile-fail/retslot-cast.rs | 6 +- src/test/compile-fail/self-impl.rs | 40 + src/test/compile-fail/shadowed-lifetime.rs | 11 +- .../stability-attribute-non-staged.rs | 14 + .../compile-fail/struct-base-wrong-type-2.rs | 31 + .../compile-fail/struct-base-wrong-type.rs | 21 +- .../trait-as-struct-constructor.rs | 2 +- .../trait-bounds-impl-comparison-1.rs | 3 +- .../trait-bounds-impl-comparison-2.rs | 1 - .../trait-bounds-on-structs-and-enums.rs | 4 +- src/test/compile-fail/trait-bounds-sugar.rs | 4 +- src/test/compile-fail/trait-impl-1.rs | 4 +- .../type-params-in-different-spaces-1.rs | 6 +- ...-default-trait-impl-constituent-types-2.rs | 4 +- ...ck-default-trait-impl-constituent-types.rs | 4 +- .../typeck-default-trait-impl-negation.rs | 6 +- ...typeck-default-trait-impl-outside-crate.rs | 2 - .../typeck-default-trait-impl-precedence.rs | 6 +- .../typeck-default-trait-impl-superregion.rs | 2 - .../typeck-default-trait-impl-supertrait.rs | 4 +- ...k-default-trait-impl-trait-where-clause.rs | 6 +- .../unboxed-closure-sugar-equiv.rs | 4 +- .../unboxed-closure-sugar-lifetime-elision.rs | 2 +- .../unboxed-closure-sugar-not-used-on-fn.rs | 2 +- ...r-wrong-number-number-type-parameters-1.rs | 2 +- ...r-wrong-number-number-type-parameters-3.rs | 2 +- ...gar-wrong-number-number-type-parameters.rs | 2 +- .../unboxed-closure-sugar-wrong-trait.rs | 2 +- src/test/compile-fail/unsized6.rs | 4 +- src/test/compile-fail/unsized7.rs | 4 +- src/test/compile-fail/unsupported-cast.rs | 5 +- ...use-after-move-implicity-coerced-object.rs | 2 - src/test/compile-fail/variadic-ffi-3.rs | 43 + src/test/compile-fail/variadic-ffi.rs | 29 +- .../variance-contravariant-arg-object.rs | 6 +- .../variance-contravariant-arg-trait-match.rs | 7 +- ...variance-contravariant-self-trait-match.rs | 8 +- .../variance-covariant-arg-object.rs | 6 +- .../variance-covariant-arg-trait-match.rs | 6 +- .../variance-covariant-self-trait-match.rs | 6 +- .../compile-fail/variance-region-bounds.rs | 4 +- .../variance-regions-unused-direct.rs | 2 +- .../compile-fail/variance-trait-bounds.rs | 10 +- .../compile-fail/variance-trait-matching.rs | 45 +- .../compile-fail/variance-types-bounds.rs | 10 +- .../variance-unused-region-param.rs | 2 +- .../variance-unused-type-param.rs | 4 - .../wrong-mul-method-signature.rs | 13 +- src/test/debuginfo/associated-types.rs | 2 +- src/test/debuginfo/borrowed-enum.rs | 6 +- src/test/debuginfo/borrowed-tuple.rs | 6 +- src/test/debuginfo/box.rs | 2 +- .../by-value-non-immediate-argument.rs | 6 +- .../by-value-self-argument-in-trait-impl.rs | 2 +- .../debuginfo/c-style-enum-in-composite.rs | 8 +- src/test/debuginfo/cross-crate-spans.rs | 4 +- .../debuginfo/destructured-fn-argument.rs | 12 +- .../destructured-for-loop-variable.rs | 2 +- src/test/debuginfo/destructured-local.rs | 12 +- .../debuginfo/function-arg-initialization.rs | 22 +- ...nction-prologue-stepping-no-stack-check.rs | 26 +- .../function-prologue-stepping-regular.rs | 3 +- src/test/debuginfo/gdb-pretty-std.rs | 1 - ...gdb-pretty-struct-and-enums-pre-gdb-7-7.rs | 1 + src/test/debuginfo/generic-function.rs | 6 +- .../generic-method-on-generic-struct.rs | 4 +- .../debuginfo/generic-tuple-style-enum.rs | 8 +- src/test/debuginfo/issue13213.rs | 2 +- src/test/debuginfo/method-on-enum.rs | 4 +- .../debuginfo/method-on-generic-struct.rs | 4 +- src/test/debuginfo/method-on-tuple-struct.rs | 10 +- src/test/debuginfo/option-like-enum.rs | 10 +- src/test/debuginfo/simd.rs | 22 +- src/test/debuginfo/simple-tuple.rs | 42 +- src/test/debuginfo/struct-in-enum.rs | 6 +- src/test/debuginfo/tuple-in-struct.rs | 22 +- src/test/debuginfo/tuple-in-tuple.rs | 14 +- src/test/debuginfo/tuple-struct.rs | 12 +- src/test/debuginfo/tuple-style-enum.rs | 8 +- src/test/debuginfo/unique-enum.rs | 6 +- src/test/debuginfo/vec-slices.rs | 4 +- src/test/parse-fail/issue-22647.rs | 2 +- src/test/parse-fail/issue-22712.rs | 2 +- src/test/parse-fail/issue-24197.rs | 13 + src/test/parse-fail/issue-24375.rs | 19 + src/test/parse-fail/issue-5806.rs | 1 + src/test/parse-fail/match-vec-invalid.rs | 2 +- src/test/parse-fail/omitted-arg-in-item-fn.rs | 2 +- .../pat-lt-bracket-1.rs} | 2 +- src/test/parse-fail/pat-lt-bracket-2.rs | 12 + .../pat-lt-bracket-3.rs} | 2 +- src/test/parse-fail/pat-lt-bracket-4.rs | 21 + src/test/parse-fail/pat-lt-bracket-5.rs | 13 + src/test/parse-fail/pat-lt-bracket-6.rs | 13 + src/test/parse-fail/pat-lt-bracket-7.rs | 13 + src/test/parse-fail/pat-ranges-1.rs | 15 + src/test/parse-fail/pat-ranges-2.rs | 15 + src/test/parse-fail/pat-ranges-3.rs | 15 + src/test/parse-fail/pat-ranges-4.rs | 15 + .../parse-fail/removed-syntax-larrow-init.rs | 2 +- .../struct-literal-in-match-discriminant.rs | 2 +- .../wrong-escape-of-curly-braces.rs | 18 + src/test/pretty/default-trait-impl.rs | 6 +- src/test/run-fail/diverging-closure.rs | 18 + src/test/run-fail/overflowing-neg.rs | 19 + src/test/run-fail/panic-task-name-owned.rs | 4 +- .../run-fail/rt-set-exit-status-panic2.rs | 2 +- .../c-link-to-rust-staticlib/Makefile | 2 +- src/test/run-make/include_bytes_deps/Makefile | 21 + .../run-make/include_bytes_deps/input.bin | 1 + .../run-make/include_bytes_deps/input.txt | 1 + .../run-make/include_bytes_deps/main.rs} | 8 +- src/test/run-make/issue-14500/Makefile | 4 + src/test/run-make/issue-22131/foo.rs | 2 - src/test/run-make/issue-24445/Makefile | 12 + .../bar.rs => issue-24445/foo.c} | 8 +- src/test/run-make/issue-24445/foo.rs | 25 + src/test/run-make/lto-smoke-c/Makefile | 2 +- src/test/run-make/no-stack-check/Makefile | 9 +- .../run-make/rustdoc-assoc-types/Makefile | 5 - .../run-make/rustdoc-default-impl/Makefile | 5 - .../rustdoc-extern-default-method/Makefile | 6 - .../run-make/rustdoc-extern-method/Makefile | 7 - src/test/run-make/rustdoc-ffi/Makefile | 8 - .../run-make/rustdoc-hidden-line/Makefile | 15 - src/test/run-make/rustdoc-must-use/Makefile | 5 - .../run-make/rustdoc-negative-impl/Makefile | 5 - src/test/run-make/rustdoc-recursion/Makefile | 11 - .../run-make/rustdoc-search-index/Makefile | 15 - src/test/run-make/rustdoc-smoke/Makefile | 4 - src/test/run-make/rustdoc-src-links/Makefile | 5 - src/test/run-make/rustdoc-src-links/foo.rs | 43 - .../run-make/rustdoc-src-links/qux/mod.rs | 39 - .../run-make/rustdoc-viewpath-self/Makefile | 5 - src/test/run-make/rustdoc-where/Makefile | 5 - src/test/run-make/save-analysis/SubDir/mod.rs | 7 +- src/test/run-make/save-analysis/foo.rs | 58 +- src/test/run-make/simd-ffi/simd.rs | 8 +- .../run-make/symbols-are-reasonable/lib.rs | 2 +- src/test/run-make/target-specs/foo.rs | 8 +- src/test/run-make/tools.mk | 12 +- .../run-make/unicode-input/multiple_files.rs | 2 +- .../run-make/unicode-input/span_length.rs | 2 +- .../run-make/use-extern-for-plugins/Makefile | 7 +- .../issue-15149.rs | 15 +- .../run-pass-fulldeps/llvm-pass-plugin.rs | 17 + src/test/run-pass-fulldeps/quote-tokens.rs | 1 + .../run-pass-fulldeps/rename-directory.rs | 1 - src/test/run-pass-valgrind/cleanup-stdin.rs | 5 +- src/test/run-pass/argument-passing.rs | 1 - src/test/run-pass/arith-2.rs | 1 - src/test/run-pass/arith-unsigned.rs | 1 - src/test/run-pass/artificial-block.rs | 1 - src/test/run-pass/as-precedence.rs | 1 - src/test/run-pass/asm-in-out-operand.rs | 1 - src/test/run-pass/asm-out-assign.rs | 1 - src/test/run-pass/assign-assign.rs | 1 - src/test/run-pass/assignability-trait.rs | 1 - src/test/run-pass/associated-types-basic.rs | 8 +- .../associated-types-binding-in-trait.rs | 1 - src/test/run-pass/associated-types-bound.rs | 1 - .../associated-types-constant-type.rs | 1 - ...ciated-types-doubleendediterator-object.rs | 1 - .../associated-types-enum-field-named.rs | 1 - .../associated-types-enum-field-numbered.rs | 1 - .../associated-types-in-default-method.rs | 1 - src/test/run-pass/associated-types-in-fn.rs | 1 - .../associated-types-in-impl-generics.rs | 1 - .../associated-types-in-inherent-method.rs | 1 - .../run-pass/associated-types-issue-20220.rs | 1 - .../run-pass/associated-types-issue-20371.rs | 6 +- .../run-pass/associated-types-issue-21212.rs | 1 - .../associated-types-iterator-binding.rs | 1 - .../associated-types-nested-projections.rs | 3 +- ...iated-types-normalize-in-bounds-binding.rs | 5 +- ...om-type-param-via-bound-in-where-clause.rs | 8 +- ...ypes-projection-from-known-type-in-impl.rs | 1 - ...sociated-types-projection-in-supertrait.rs | 1 - ...ted-types-projection-to-unrelated-trait.rs | 43 + .../associated-types-ref-in-struct-literal.rs | 1 - src/test/run-pass/associated-types-return.rs | 1 - src/test/run-pass/associated-types-simple.rs | 1 - src/test/run-pass/associated-types-stream.rs | 1 - .../associated-types-struct-field-named.rs | 1 - .../associated-types-struct-field-numbered.rs | 1 - .../run-pass/associated-types-sugar-path.rs | 1 - src/test/run-pass/atomic-print.rs | 48 + src/test/run-pass/attr-main-2.rs | 1 - src/test/run-pass/attr-no-drop-flag-size.rs | 1 - src/test/run-pass/auto-loop.rs | 1 - src/test/run-pass/auto-ref-sliceable.rs | 1 - src/test/run-pass/autobind.rs | 1 - .../run-pass/autoderef-method-on-trait.rs | 3 +- .../run-pass/autoderef-method-priority.rs | 1 - .../autoderef-method-twice-but-not-thrice.rs | 1 - src/test/run-pass/autoderef-method-twice.rs | 1 - src/test/run-pass/autoderef-method.rs | 1 - .../autoref-intermediate-types-issue-3585.rs | 1 - src/test/run-pass/backtrace.rs | 32 +- src/test/run-pass/big-literals.rs | 1 - .../run-pass/binary-minus-without-space.rs | 1 - src/test/run-pass/bind-by-move.rs | 1 - .../bind-field-short-with-modifiers.rs | 1 - src/test/run-pass/block-arg-call-as.rs | 1 - src/test/run-pass/block-expr-precedence.rs | 1 - src/test/run-pass/block-fn-coerce.rs | 1 - src/test/run-pass/bool-not.rs | 1 - src/test/run-pass/bool.rs | 1 - src/test/run-pass/borrow-tuple-fields.rs | 1 - .../borrowck-borrow-from-expr-block.rs | 1 - .../run-pass/borrowck-closures-two-imm.rs | 1 - .../run-pass/borrowck-fixed-length-vecs.rs | 1 - .../run-pass/borrowck-freeze-frozen-mut.rs | 1 - .../borrowck-macro-interaction-issue-6304.rs | 1 - .../run-pass/borrowck-move-by-capture-ok.rs | 1 - .../run-pass/borrowck-mut-vec-as-imm-slice.rs | 1 - .../borrowck-pat-reassign-no-binding.rs | 1 - src/test/run-pass/borrowck-rvalues-mutable.rs | 1 - .../borrowck-scope-of-deref-issue-4666.rs | 1 - src/test/run-pass/borrowck-univariant-enum.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-2.rs | 1 - src/test/run-pass/borrowed-ptr-pattern-3.rs | 1 - .../borrowed-ptr-pattern-infallible.rs | 1 - .../run-pass/borrowed-ptr-pattern-option.rs | 1 - src/test/run-pass/borrowed-ptr-pattern.rs | 1 - src/test/run-pass/break.rs | 1 - src/test/run-pass/bug-7183-generics.rs | 1 - ...ltin-superkinds-capabilities-transitive.rs | 1 - .../builtin-superkinds-capabilities-xc.rs | 1 - .../builtin-superkinds-capabilities.rs | 1 - .../run-pass/builtin-superkinds-self-type.rs | 1 - .../run-pass/by-value-self-in-mut-slot.rs | 1 - src/test/run-pass/c-stack-returning-int64.rs | 1 - .../call-closure-from-overloaded-op.rs | 1 - .../capture-clauses-boxed-closures.rs | 1 - .../capture-clauses-unboxed-closures.rs | 1 - src/test/run-pass/capturing-logging.rs | 47 - src/test/run-pass/cast.rs | 1 - src/test/run-pass/cci_nested_exe.rs | 1 - src/test/run-pass/cell-does-not-clone.rs | 1 - src/test/run-pass/cfg-macros-foo.rs | 1 - src/test/run-pass/cfg-macros-notfoo.rs | 1 - src/test/run-pass/cfgs-on-items.rs | 1 - src/test/run-pass/char.rs | 1 - src/test/run-pass/check-static-mut-slices.rs | 1 - src/test/run-pass/check-static-slice.rs | 1 - src/test/run-pass/class-exports.rs | 1 - src/test/run-pass/class-method-cross-crate.rs | 1 - .../run-pass/class-methods-cross-crate.rs | 1 - src/test/run-pass/class-methods.rs | 1 - .../class-poly-methods-cross-crate.rs | 1 - src/test/run-pass/class-poly-methods.rs | 1 - src/test/run-pass/classes-cross-crate.rs | 1 - .../run-pass/classes-simple-cross-crate.rs | 1 - src/test/run-pass/classes-simple-method.rs | 1 - src/test/run-pass/classes-simple.rs | 1 - .../cleanup-rvalue-during-if-and-while.rs | 1 - ...nup-rvalue-temp-during-incomplete-alloc.rs | 1 - src/test/run-pass/clone-with-exterior.rs | 5 +- src/test/run-pass/closure-inference.rs | 1 - src/test/run-pass/closure-inference2.rs | 1 - src/test/run-pass/closure-reform.rs | 6 +- src/test/run-pass/cmp-default.rs | 1 - .../run-pass/coerce-reborrow-imm-ptr-rcvr.rs | 1 - .../run-pass/coerce-reborrow-imm-vec-rcvr.rs | 1 - .../run-pass/coerce-reborrow-mut-vec-arg.rs | 1 - .../run-pass/coerce-reborrow-mut-vec-rcvr.rs | 1 - .../coherence-subtyping.rs | 4 +- src/test/run-pass/coherence_copy_like.rs | 4 +- src/test/run-pass/comm.rs | 3 +- src/test/run-pass/compare-generic-enums.rs | 1 - src/test/run-pass/concat.rs | 1 - src/test/run-pass/conditional-compile.rs | 1 - .../run-pass/conditional-debug-macro-off.rs | 1 - src/test/run-pass/const-autoderef.rs | 1 - src/test/run-pass/const-big-enum.rs | 1 - src/test/run-pass/const-binops.rs | 2 - .../run-pass/const-block-cross-crate-fn.rs | 1 - .../const-block-item-macro-codegen.rs | 1 - src/test/run-pass/const-block-item.rs | 1 - src/test/run-pass/const-block.rs | 1 - src/test/run-pass/const-cast-ptr-int.rs | 1 - src/test/run-pass/const-cast.rs | 1 - src/test/run-pass/const-const.rs | 1 - src/test/run-pass/const-contents.rs | 1 - src/test/run-pass/const-cross-crate-const.rs | 1 - src/test/run-pass/const-cross-crate-extern.rs | 1 - src/test/run-pass/const-deref.rs | 1 - src/test/run-pass/const-enum-byref-self.rs | 1 - src/test/run-pass/const-enum-byref.rs | 1 - src/test/run-pass/const-enum-cast.rs | 1 - src/test/run-pass/const-enum-ptr.rs | 1 - src/test/run-pass/const-enum-struct.rs | 1 - src/test/run-pass/const-enum-struct2.rs | 1 - src/test/run-pass/const-enum-structlike.rs | 1 - src/test/run-pass/const-enum-tuple.rs | 1 - src/test/run-pass/const-enum-tuple2.rs | 1 - src/test/run-pass/const-enum-tuplestruct.rs | 1 - src/test/run-pass/const-enum-tuplestruct2.rs | 1 - src/test/run-pass/const-enum-vec-index.rs | 1 - src/test/run-pass/const-enum-vec-ptr.rs | 1 - src/test/run-pass/const-enum-vector.rs | 1 - src/test/run-pass/const-extern-function.rs | 1 - src/test/run-pass/const-fn-val.rs | 1 - src/test/run-pass/const-negative.rs | 1 - src/test/run-pass/const-nullary-enum.rs | 1 - .../run-pass/const-nullary-univariant-enum.rs | 1 - .../run-pass/const-region-ptrs-noncopy.rs | 1 - src/test/run-pass/const-str-ptr.rs | 1 - src/test/run-pass/const-tuple-struct.rs | 1 - src/test/run-pass/consts-in-patterns.rs | 1 - src/test/run-pass/core-run-destroy.rs | 69 +- .../cross-crate-newtype-struct-pat.rs | 1 - src/test/run-pass/cycle-generic-bound.rs | 4 +- src/test/run-pass/deep.rs | 1 - src/test/run-pass/deref-mut-on-ref.rs | 1 - src/test/run-pass/deref-on-ref.rs | 1 - src/test/run-pass/deref-rc.rs | 1 - src/test/run-pass/derive-no-std.rs | 1 - .../run-pass/deriving-cmp-generic-enum.rs | 1 - .../deriving-cmp-generic-struct-enum.rs | 1 - .../run-pass/deriving-cmp-generic-struct.rs | 1 - .../deriving-cmp-generic-tuple-struct.rs | 1 - .../run-pass/deriving-cmp-shortcircuit.rs | 1 - src/test/run-pass/deriving-default-box.rs | 1 - .../deriving-encodable-decodable-box.rs | 1 - ...riving-encodable-decodable-cell-refcell.rs | 1 - src/test/run-pass/deriving-global.rs | 7 +- src/test/run-pass/deriving-hash.rs | 1 - src/test/run-pass/deriving-primitive.rs | 39 - src/test/run-pass/deriving-rand.rs | 44 - src/test/run-pass/destructure-array-1.rs | 1 - src/test/run-pass/die-macro.rs | 1 - src/test/run-pass/discriminant_value.rs | 77 + src/test/run-pass/div-mod.rs | 1 - src/test/run-pass/drop-flag-sanity-check.rs | 4 +- .../run-pass/drop-flag-skip-sanity-check.rs | 9 +- src/test/run-pass/drop-struct-as-object.rs | 1 - .../run-pass/drop-with-type-ascription-1.rs | 1 - .../run-pass/drop-with-type-ascription-2.rs | 1 - src/test/run-pass/dropck_tarena_sound_drop.rs | 1 - src/test/run-pass/dst-deref-mut.rs | 1 - src/test/run-pass/dst-deref.rs | 1 - src/test/run-pass/dst-index.rs | 1 - src/test/run-pass/dst-raw.rs | 1 - src/test/run-pass/dst-struct-sole.rs | 5 +- src/test/run-pass/dst-struct.rs | 5 +- src/test/run-pass/dst-trait.rs | 1 - src/test/run-pass/early-ret-binop-add.rs | 4 +- src/test/run-pass/else-if.rs | 1 - .../run-pass/empty-allocation-non-null.rs | 1 - src/test/run-pass/enum-alignment.rs | 1 - src/test/run-pass/enum-clike-ffi-as-int.rs | 1 - src/test/run-pass/enum-discr.rs | 1 - src/test/run-pass/enum-discrim-autosizing.rs | 1 - .../run-pass/enum-discrim-manual-sizing.rs | 1 - src/test/run-pass/enum-disr-val-pretty.rs | 1 - src/test/run-pass/enum-null-pointer-opt.rs | 1 - .../enum-nullable-const-null-with-fields.rs | 1 - .../enum-nullable-simplifycfg-misopt.rs | 1 - src/test/run-pass/env-home-dir.rs | 1 - src/test/run-pass/env-vars.rs | 1 - src/test/run-pass/eq-multidispatch.rs | 1 - src/test/run-pass/estr-uniq.rs | 1 - src/test/run-pass/exec-env.rs | 1 - src/test/run-pass/explicit-self-generic.rs | 1 - .../run-pass/explicit-self-objects-uniq.rs | 1 - src/test/run-pass/explicit-self.rs | 1 - src/test/run-pass/exponential-notation.rs | 40 - src/test/run-pass/expr-block-fn.rs | 1 - .../run-pass/expr-block-generic-unique2.rs | 1 - src/test/run-pass/expr-block-generic.rs | 1 - src/test/run-pass/expr-block-slot.rs | 1 - src/test/run-pass/expr-block-unique.rs | 1 - src/test/run-pass/expr-block.rs | 1 - src/test/run-pass/expr-copy.rs | 1 - src/test/run-pass/expr-fn.rs | 1 - src/test/run-pass/expr-if-generic.rs | 1 - src/test/run-pass/expr-if-panic-all.rs | 1 - src/test/run-pass/expr-if-panic.rs | 1 - src/test/run-pass/expr-if-unique.rs | 1 - src/test/run-pass/expr-if.rs | 1 - .../run-pass/expr-match-generic-unique1.rs | 1 - .../run-pass/expr-match-generic-unique2.rs | 1 - src/test/run-pass/expr-match-generic.rs | 1 - src/test/run-pass/expr-match-panic-all.rs | 1 - src/test/run-pass/expr-match-panic.rs | 1 - src/test/run-pass/expr-match-unique.rs | 1 - src/test/run-pass/expr-match.rs | 1 - src/test/run-pass/ext-expand-inner-exprs.rs | 1 - src/test/run-pass/exterior.rs | 1 - src/test/run-pass/extern-call-deep2.rs | 2 +- src/test/run-pass/extern-call-direct.rs | 1 - src/test/run-pass/extern-call-scrub.rs | 4 +- .../extern-compare-with-return-type.rs | 1 - src/test/run-pass/extern-methods.rs | 8 +- src/test/run-pass/extern-pass-char.rs | 1 - src/test/run-pass/extern-pass-double.rs | 1 - src/test/run-pass/extern-pass-u32.rs | 1 - src/test/run-pass/extern-pass-u64.rs | 1 - src/test/run-pass/extern-return-TwoU16s.rs | 1 - src/test/run-pass/extern-return-TwoU32s.rs | 1 - src/test/run-pass/extern-return-TwoU64s.rs | 1 - src/test/run-pass/extern-return-TwoU8s.rs | 1 - src/test/run-pass/extern-take-value.rs | 1 - .../run-pass/extoption_env-not-defined.rs | 1 - src/test/run-pass/fds-are-cloexec.rs | 73 + src/test/run-pass/field-destruction-order.rs | 1 - src/test/run-pass/fixed_length_copy.rs | 1 - src/test/run-pass/float-nan.rs | 12 +- src/test/run-pass/float2.rs | 1 - src/test/run-pass/floatlits.rs | 1 - src/test/run-pass/fmt-pointer-trait.rs | 35 + src/test/run-pass/fn-bare-assign.rs | 1 - src/test/run-pass/fn-bare-size.rs | 1 - src/test/run-pass/fn-bare-spawn.rs | 1 - src/test/run-pass/fn-item-type-cast.rs | 1 - src/test/run-pass/fn-pattern-expected-type.rs | 1 - src/test/run-pass/for-destruct.rs | 1 - src/test/run-pass/for-loop-goofiness.rs | 1 - src/test/run-pass/for-loop-into-iterator.rs | 1 - src/test/run-pass/for-loop-panic.rs | 1 - .../foreach-external-iterators-break.rs | 1 - ...xternal-iterators-hashmap-break-restart.rs | 1 - .../foreach-external-iterators-hashmap.rs | 1 - .../foreach-external-iterators-loop.rs | 1 - .../foreach-external-iterators-nested.rs | 1 - .../run-pass/foreach-external-iterators.rs | 1 - src/test/run-pass/foreach-nested.rs | 1 - src/test/run-pass/foreign-fn-linkname.rs | 1 - src/test/run-pass/foreign-fn-with-byval.rs | 1 - src/test/run-pass/format-nan.rs | 1 - src/test/run-pass/format-ref-cell.rs | 1 - src/test/run-pass/fsu-moves-and-copies.rs | 1 - src/test/run-pass/fun-call-variants.rs | 1 - src/test/run-pass/fun-indirect-call.rs | 1 - .../run-pass/func-arg-incomplete-pattern.rs | 1 - src/test/run-pass/func-arg-ref-pattern.rs | 1 - src/test/run-pass/func-arg-wild-pattern.rs | 1 - src/test/run-pass/generic-exterior-unique.rs | 1 - src/test/run-pass/generic-extern-mangle.rs | 1 - src/test/run-pass/generic-fn-infer.rs | 1 - src/test/run-pass/generic-object.rs | 1 - src/test/run-pass/generic-static-methods.rs | 1 - src/test/run-pass/generic-type.rs | 1 - src/test/run-pass/generic-unique.rs | 1 - src/test/run-pass/getopts_ref.rs | 1 - src/test/run-pass/global-scope.rs | 1 - src/test/run-pass/guards-not-exhaustive.rs | 1 - src/test/run-pass/guards.rs | 1 - .../run-pass/hrtb-fn-like-trait-object.rs | 1 - src/test/run-pass/hrtb-fn-like-trait.rs | 1 - .../hrtb-trait-object-paren-notation.rs | 1 - src/test/run-pass/huge-largest-array.rs | 1 - src/test/run-pass/hygiene-dodging-1.rs | 1 - src/test/run-pass/hygienic-labels-in-let.rs | 8 + src/test/run-pass/hygienic-labels.rs | 6 +- src/test/run-pass/i32-sub.rs | 1 - src/test/run-pass/i8-incr.rs | 1 - src/test/run-pass/if-let.rs | 1 - src/test/run-pass/ifmt.rs | 20 +- .../run-pass/impl-inherent-non-conflict.rs | 1 - .../impl-inherent-prefer-over-trait.rs | 1 - .../run-pass/impl-not-adjacent-to-type.rs | 1 - src/test/run-pass/import-glob-crate.rs | 1 - .../inferred-suffix-in-pattern-range.rs | 1 - .../run-pass/inherent-trait-method-order.rs | 1 - src/test/run-pass/init-large-type.rs | 2 +- src/test/run-pass/init-res-into-things.rs | 1 - src/test/run-pass/inner-attrs-on-impl.rs | 1 - src/test/run-pass/inner-static.rs | 1 - src/test/run-pass/integer-literal-radix.rs | 1 - src/test/run-pass/intrinsic-alignment.rs | 1 - src/test/run-pass/intrinsic-assume.rs | 1 - src/test/run-pass/intrinsic-atomics-cc.rs | 1 - src/test/run-pass/intrinsic-atomics.rs | 1 - src/test/run-pass/intrinsic-move-val.rs | 1 - src/test/run-pass/intrinsic-return-address.rs | 1 - src/test/run-pass/intrinsic-unreachable.rs | 1 - src/test/run-pass/intrinsics-integer.rs | 1 - src/test/run-pass/intrinsics-math.rs | 2 - src/test/run-pass/issue-10392.rs | 1 - src/test/run-pass/issue-10626.rs | 6 +- src/test/run-pass/issue-10734.rs | 1 - src/test/run-pass/issue-10802.rs | 1 - src/test/run-pass/issue-1112.rs | 1 - src/test/run-pass/issue-11552.rs | 1 - src/test/run-pass/issue-11577.rs | 1 - src/test/run-pass/issue-11677.rs | 1 - src/test/run-pass/issue-11736.rs | 3 - src/test/run-pass/issue-11881.rs | 1 - src/test/run-pass/issue-11940.rs | 1 - src/test/run-pass/issue-12285.rs | 1 - src/test/run-pass/issue-12677.rs | 1 - src/test/run-pass/issue-12684.rs | 26 - src/test/run-pass/issue-12699.rs | 9 +- src/test/run-pass/issue-12860.rs | 2 +- src/test/run-pass/issue-13105.rs | 6 +- src/test/run-pass/issue-13204.rs | 1 - .../run-pass/issue-13259-windows-tcb-trash.rs | 2 +- src/test/run-pass/issue-13323.rs | 1 - src/test/run-pass/issue-13494.rs | 3 +- src/test/run-pass/issue-13507-2.rs | 1 - src/test/run-pass/issue-13763.rs | 2 +- src/test/run-pass/issue-13867.rs | 1 - src/test/run-pass/issue-14308.rs | 1 - src/test/run-pass/issue-14456.rs | 1 - src/test/run-pass/issue-14865.rs | 1 - src/test/run-pass/issue-14901.rs | 6 +- src/test/run-pass/issue-14936.rs | 1 - src/test/run-pass/issue-14940.rs | 1 - src/test/run-pass/issue-15080.rs | 1 - src/test/run-pass/issue-15104.rs | 1 - src/test/run-pass/issue-15129.rs | 1 - src/test/run-pass/issue-15523-big.rs | 48 + src/test/run-pass/issue-15523.rs | 51 + src/test/run-pass/issue-15562.rs | 3 - src/test/run-pass/issue-15673.rs | 4 +- src/test/run-pass/issue-15689-1.rs | 1 - src/test/run-pass/issue-15734.rs | 1 - src/test/run-pass/issue-15763.rs | 8 +- src/test/run-pass/issue-15793.rs | 1 - src/test/run-pass/issue-15858.rs | 1 - .../issue-15881-model-lexer-dotdotdot.rs | 1 - src/test/run-pass/issue-16151.rs | 1 - src/test/run-pass/issue-16530.rs | 1 - src/test/run-pass/issue-16560.rs | 1 - src/test/run-pass/issue-16596.rs | 1 - src/test/run-pass/issue-16602-1.rs | 15 + src/test/run-pass/issue-16602-2.rs | 21 + src/test/run-pass/issue-16602-3.rs | 34 + src/test/run-pass/issue-16648.rs | 1 - src/test/run-pass/issue-16739.rs | 1 - src/test/run-pass/issue-16774.rs | 1 - src/test/run-pass/issue-1701.rs | 1 - src/test/run-pass/issue-17068.rs | 1 - src/test/run-pass/issue-17074.rs | 1 - src/test/run-pass/issue-17216.rs | 1 - src/test/run-pass/issue-17233.rs | 1 - src/test/run-pass/issue-17302.rs | 1 - src/test/run-pass/issue-17662.rs | 1 - src/test/run-pass/issue-17718-parse-const.rs | 1 - src/test/run-pass/issue-17718.rs | 1 - src/test/run-pass/issue-17734.rs | 1 - src/test/run-pass/issue-17877.rs | 1 - src/test/run-pass/issue-18352.rs | 1 - src/test/run-pass/issue-18412.rs | 1 - src/test/run-pass/issue-18652.rs | 1 - src/test/run-pass/issue-18738.rs | 2 - src/test/run-pass/issue-18767.rs | 1 - src/test/run-pass/issue-18859.rs | 1 - .../{issue-18619.rs => issue-19097.rs} | 15 +- src/test/run-pass/issue-19244.rs | 1 - .../run-pass/issue-19811-escape-unicode.rs | 1 - src/test/run-pass/issue-20454.rs | 4 +- src/test/run-pass/issue-20676.rs | 1 - src/test/run-pass/issue-21058.rs | 1 - src/test/run-pass/issue-21245.rs | 6 +- src/test/run-pass/issue-21291.rs | 17 + src/test/run-pass/issue-21306.rs | 1 - src/test/run-pass/issue-21361.rs | 1 - src/test/run-pass/issue-21384.rs | 1 - src/test/run-pass/issue-21400.rs | 66 + src/test/run-pass/issue-21486.rs | 86 + src/test/run-pass/issue-21634.rs | 1 - src/test/run-pass/issue-21655.rs | 1 - src/test/run-pass/issue-21721.rs | 1 - src/test/run-pass/issue-22036.rs | 1 - src/test/run-pass/issue-2214.rs | 1 - src/test/run-pass/issue-22356.rs | 4 +- .../run-pass/issue-22536-copy-mustnt-zero.rs | 1 - src/test/run-pass/issue-22546.rs | 54 + src/test/run-pass/issue-2311-2.rs | 1 - src/test/run-pass/issue-2312.rs | 1 - .../issue-23338-ensure-param-drop-order.rs | 171 + ...ssue-23338-params-outlive-temps-of-body.rs | 39 + src/test/run-pass/issue-24161.rs | 19 + src/test/run-pass/issue-2428.rs | 1 - src/test/run-pass/issue-24434.rs | 16 + src/test/run-pass/issue-2611-3.rs | 1 - src/test/run-pass/issue-2735-2.rs | 1 - src/test/run-pass/issue-2735-3.rs | 1 - src/test/run-pass/issue-2748-b.rs | 1 - src/test/run-pass/issue-2895.rs | 1 - src/test/run-pass/issue-2904.rs | 8 +- src/test/run-pass/issue-2936.rs | 1 - src/test/run-pass/issue-3091.rs | 1 - src/test/run-pass/issue-3290.rs | 1 - src/test/run-pass/issue-333.rs | 1 - src/test/run-pass/issue-3424.rs | 17 +- src/test/run-pass/issue-3556.rs | 2 +- src/test/run-pass/issue-3574.rs | 1 - src/test/run-pass/issue-3609.rs | 4 +- src/test/run-pass/issue-3895.rs | 1 - src/test/run-pass/issue-3935.rs | 1 - src/test/run-pass/issue-3979-generics.rs | 1 - src/test/run-pass/issue-3979-xcrate.rs | 1 - src/test/run-pass/issue-3979.rs | 1 - src/test/run-pass/issue-4016.rs | 1 - src/test/run-pass/issue-4107.rs | 1 - src/test/run-pass/issue-4446.rs | 7 +- src/test/run-pass/issue-4448.rs | 1 - src/test/run-pass/issue-4734.rs | 1 - src/test/run-pass/issue-5239-2.rs | 1 - src/test/run-pass/issue-5521.rs | 1 - src/test/run-pass/issue-5530.rs | 1 - src/test/run-pass/issue-5917.rs | 1 - src/test/run-pass/issue-5988.rs | 5 +- src/test/run-pass/issue-5997.rs | 1 - src/test/run-pass/issue-6128.rs | 1 - src/test/run-pass/issue-6130.rs | 1 - src/test/run-pass/issue-6153.rs | 1 - src/test/run-pass/issue-6334.rs | 1 - src/test/run-pass/issue-6449.rs | 1 - src/test/run-pass/issue-6892.rs | 1 - src/test/run-pass/issue-7575.rs | 1 - src/test/run-pass/issue-7663.rs | 1 - src/test/run-pass/issue-7784.rs | 1 - src/test/run-pass/issue-8351-1.rs | 1 - src/test/run-pass/issue-8351-2.rs | 1 - src/test/run-pass/issue-8391.rs | 1 - src/test/run-pass/issue-8398.rs | 8 +- src/test/run-pass/issue-8460.rs | 50 +- src/test/run-pass/issue-8498.rs | 1 - src/test/run-pass/issue-8709.rs | 1 - src/test/run-pass/issue-8860.rs | 1 - src/test/run-pass/issue-8898.rs | 1 - src/test/run-pass/issue-9188.rs | 1 - src/test/run-pass/issue-9259.rs | 1 - .../issue-9394-inherited-trait-calls.rs | 1 - src/test/run-pass/issue-9396.rs | 12 +- src/test/run-pass/issue-979.rs | 1 - src/test/run-pass/issue-9918.rs | 1 - src/test/run-pass/issue24353.rs | 16 + src/test/run-pass/item-attributes.rs | 1 - .../run-pass/iter-cloned-type-inference.rs | 5 +- src/test/run-pass/ivec-tag.rs | 3 +- .../kindck-implicit-close-over-mut-var.rs | 11 +- .../run-pass/kindck-owned-trait-contains-1.rs | 1 - src/test/run-pass/last-use-in-block.rs | 1 - src/test/run-pass/last-use-in-cap-clause.rs | 1 - src/test/run-pass/let-destruct-ref.rs | 1 - src/test/run-pass/let-var-hygiene.rs | 1 - src/test/run-pass/logging-enabled-debug.rs | 1 - src/test/run-pass/logging-enabled.rs | 1 - src/test/run-pass/logging-separate-lines.rs | 6 +- src/test/run-pass/loop-break-cont-1.rs | 1 - src/test/run-pass/loop-scope.rs | 1 - src/test/run-pass/macro-block-nonterminal.rs | 1 - src/test/run-pass/macro-crate-def-only.rs | 1 - src/test/run-pass/macro-crate-use.rs | 1 - src/test/run-pass/macro-deep_expansion.rs | 1 - src/test/run-pass/macro-interpolation.rs | 1 - src/test/run-pass/macro-method-issue-4621.rs | 1 - src/test/run-pass/macro-nested_stmt_macros.rs | 32 + src/test/run-pass/macro-of-higher-order.rs | 1 - src/test/run-pass/macro-pat.rs | 1 - src/test/run-pass/macro-path.rs | 1 - .../macro-stmt_macro_in_expr_macro.rs | 29 + src/test/run-pass/macro-with-attrs1.rs | 1 - src/test/run-pass/macro-with-attrs2.rs | 1 - src/test/run-pass/match-arm-statics.rs | 1 - src/test/run-pass/match-borrowed_str.rs | 1 - src/test/run-pass/match-bot-2.rs | 1 - src/test/run-pass/match-enum-struct-0.rs | 1 - src/test/run-pass/match-enum-struct-1.rs | 1 - .../run-pass/match-implicit-copy-unique.rs | 1 - src/test/run-pass/match-in-macro.rs | 1 - src/test/run-pass/match-pattern-bindings.rs | 1 - src/test/run-pass/match-pipe-binding.rs | 1 - .../match-ref-binding-in-guard-3256.rs | 1 - .../run-pass/match-ref-binding-mut-option.rs | 1 - src/test/run-pass/match-ref-binding-mut.rs | 1 - src/test/run-pass/match-ref-binding.rs | 1 - .../run-pass/match-static-const-rename.rs | 1 - src/test/run-pass/match-str.rs | 1 - src/test/run-pass/match-struct-0.rs | 1 - src/test/run-pass/match-tag.rs | 1 - src/test/run-pass/match-vec-alternatives.rs | 1 - src/test/run-pass/match-vec-rvalue.rs | 1 - ...thod-mut-self-modifies-mut-slice-lvalue.rs | 4 +- src/test/run-pass/method-projection.rs | 1 - src/test/run-pass/method-self-arg-aux1.rs | 1 - src/test/run-pass/method-self-arg-aux2.rs | 1 - src/test/run-pass/method-self-arg-trait.rs | 1 - src/test/run-pass/method-self-arg.rs | 1 - .../method-two-trait-defer-resolution-1.rs | 1 - .../method-two-trait-defer-resolution-2.rs | 3 +- src/test/run-pass/method-where-clause.rs | 1 - src/test/run-pass/mod-inside-fn.rs | 1 - src/test/run-pass/monad.rs | 1 - ...nomorphized-callees-with-ty-params-3314.rs | 6 +- src/test/run-pass/move-1-unique.rs | 1 - src/test/run-pass/move-2-unique.rs | 1 - src/test/run-pass/move-2.rs | 1 - src/test/run-pass/move-3-unique.rs | 1 - src/test/run-pass/move-4-unique.rs | 1 - src/test/run-pass/move-4.rs | 1 - src/test/run-pass/move-arg-2-unique.rs | 1 - src/test/run-pass/move-arg-2.rs | 1 - src/test/run-pass/move-arg.rs | 1 - src/test/run-pass/move-out-of-field.rs | 1 - src/test/run-pass/move-scalar.rs | 1 - .../moves-based-on-type-capture-clause.rs | 4 +- src/test/run-pass/multi-let.rs | 1 - src/test/run-pass/multidispatch1.rs | 1 - src/test/run-pass/multidispatch2.rs | 1 - src/test/run-pass/mut-function-arguments.rs | 1 - src/test/run-pass/mut-in-ident-patterns.rs | 1 - ...ility-inherits-through-fixed-length-vec.rs | 1 - src/test/run-pass/negative.rs | 1 - src/test/run-pass/nested-class.rs | 1 - .../nested-function-names-issue-8587.rs | 1 - src/test/run-pass/nested_item_main.rs | 1 - src/test/run-pass/new-unicode-escapes.rs | 1 - src/test/run-pass/newlambdas.rs | 1 - src/test/run-pass/newtype-polymorphic.rs | 1 - src/test/run-pass/newtype-struct-drop-run.rs | 1 - src/test/run-pass/no-landing-pads.rs | 1 - src/test/run-pass/non-legacy-modes.rs | 1 - src/test/run-pass/nul-characters.rs | 1 - .../run-pass/nullable-pointer-ffi-compat.rs | 1 - .../nullable-pointer-iotareduction.rs | 1 - src/test/run-pass/nullable-pointer-size.rs | 1 - src/test/run-pass/nullary-or-pattern.rs | 1 - .../run-pass/numeric-method-autoexport.rs | 10 - src/test/run-pass/object-method-numbering.rs | 1 - .../object-safety-sized-self-by-value-self.rs | 1 - ...object-safety-sized-self-generic-method.rs | 1 - .../object-safety-sized-self-return-Self.rs | 1 - .../objects-coerce-freeze-borrored.rs | 1 - ...owned-object-borrowed-method-headerless.rs | 1 - .../objects-owned-object-owned-method.rs | 1 - src/test/run-pass/once-move-out-on-heap.rs | 1 - src/test/run-pass/one-tuple.rs | 1 - src/test/run-pass/operator-associativity.rs | 1 - src/test/run-pass/option-unwrap.rs | 1 - src/test/run-pass/or-pattern.rs | 1 - src/test/run-pass/order-drop-with-match.rs | 1 - .../out-of-stack-new-thread-no-split.rs | 8 +- src/test/run-pass/out-of-stack-no-split.rs | 18 +- src/test/run-pass/out-of-stack.rs | 8 +- src/test/run-pass/out-pointer-aliasing.rs | 1 - .../run-pass/overloaded-autoderef-indexing.rs | 1 - .../run-pass/overloaded-autoderef-order.rs | 1 - .../run-pass/overloaded-autoderef-vtable.rs | 1 - .../run-pass/overloaded-autoderef-xcrate.rs | 1 - src/test/run-pass/overloaded-autoderef.rs | 4 - .../overloaded-calls-object-one-arg.rs | 1 - .../overloaded-calls-object-two-args.rs | 1 - .../overloaded-calls-object-zero-args.rs | 1 - src/test/run-pass/overloaded-calls-simple.rs | 1 - .../run-pass/overloaded-calls-zero-args.rs | 1 - src/test/run-pass/overloaded-deref-count.rs | 1 - .../run-pass/overloaded-index-assoc-list.rs | 3 +- .../run-pass/overloaded-index-autoderef.rs | 1 - .../run-pass/overloaded-index-in-field.rs | 1 - src/test/run-pass/overloaded-index.rs | 1 - .../run-pass/packed-struct-borrow-element.rs | 1 - .../run-pass/packed-struct-generic-layout.rs | 1 - .../run-pass/packed-struct-generic-size.rs | 1 - src/test/run-pass/packed-struct-layout.rs | 1 - src/test/run-pass/packed-struct-match.rs | 1 - src/test/run-pass/packed-struct-size-xc.rs | 1 - src/test/run-pass/packed-struct-size.rs | 1 - .../run-pass/packed-tuple-struct-layout.rs | 1 - src/test/run-pass/packed-tuple-struct-size.rs | 1 - .../run-pass/panic-in-dtor-drops-fields.rs | 1 - src/test/run-pass/pat-ranges.rs | 23 + .../run-pass/pattern-bound-var-in-for-each.rs | 1 - src/test/run-pass/private-class-field.rs | 1 - src/test/run-pass/process-remove-from-env.rs | 7 +- src/test/run-pass/range-type-infer.rs | 1 - src/test/run-pass/range.rs | 1 - src/test/run-pass/ranges-precedence.rs | 1 - src/test/run-pass/readalias.rs | 1 - src/test/run-pass/rec-extend.rs | 1 - src/test/run-pass/rec-tup.rs | 1 - src/test/run-pass/rec.rs | 1 - src/test/run-pass/record-pat.rs | 1 - .../reexported-static-methods-cross-crate.rs | 1 - .../run-pass/regions-borrow-evec-fixed.rs | 1 - src/test/run-pass/regions-borrow-evec-uniq.rs | 1 - src/test/run-pass/regions-borrow-uniq.rs | 1 - src/test/run-pass/regions-bot.rs | 1 - ...-close-over-type-parameter-successfully.rs | 1 - src/test/run-pass/regions-copy-closure.rs | 1 - .../run-pass/regions-dependent-addr-of.rs | 1 - ...egions-early-bound-lifetime-in-assoc-fn.rs | 4 +- .../regions-early-bound-trait-param.rs | 1 - ...egions-early-bound-used-in-bound-method.rs | 1 - .../regions-early-bound-used-in-bound.rs | 1 - .../regions-early-bound-used-in-type-param.rs | 1 - .../run-pass/regions-escape-into-other-fn.rs | 1 - .../regions-infer-borrow-scope-addr-of.rs | 1 - .../regions-infer-borrow-scope-view.rs | 1 - ...gions-infer-borrow-scope-within-loop-ok.rs | 1 - .../run-pass/regions-infer-borrow-scope.rs | 1 - src/test/run-pass/regions-infer-call-2.rs | 1 - src/test/run-pass/regions-infer-call.rs | 1 - ...regions-infer-contravariance-due-to-ret.rs | 1 - ...-lifetime-static-items-enclosing-scopes.rs | 1 - .../regions-no-variance-from-fn-generics.rs | 1 - src/test/run-pass/regions-params.rs | 1 - src/test/run-pass/regions-refcell.rs | 1 - ...ions-on-closures-to-inference-variables.rs | 1 - .../regions-return-interior-of-option.rs | 1 - src/test/run-pass/regions-trait-object-1.rs | 1 - src/test/run-pass/repeat-expr-in-static.rs | 1 - src/test/run-pass/resolve-issue-2428.rs | 1 - src/test/run-pass/resource-in-struct.rs | 1 - src/test/run-pass/return-from-closure.rs | 1 - src/test/run-pass/running-with-no-runtime.rs | 37 +- src/test/run-pass/rust-log-filter.rs | 5 +- src/test/run-pass/segfault-no-out-of-stack.rs | 7 +- src/test/run-pass/self-impl.rs | 40 +- .../self-in-mut-slot-default-method.rs | 1 - .../self-in-mut-slot-immediate-value.rs | 1 - src/test/run-pass/self-re-assign.rs | 1 - src/test/run-pass/self-shadowing-import.rs | 1 - .../run-pass/send-is-not-static-par-for.rs | 3 +- src/test/run-pass/send-resource.rs | 4 +- src/test/run-pass/send_str_hashmap.rs | 1 - src/test/run-pass/send_str_treemap.rs | 1 - src/test/run-pass/sendfn-is-a-block.rs | 1 - src/test/run-pass/sepcomp-cci.rs | 2 +- src/test/run-pass/sepcomp-extern.rs | 2 +- src/test/run-pass/sepcomp-fns-backwards.rs | 2 +- src/test/run-pass/sepcomp-fns.rs | 2 +- src/test/run-pass/sepcomp-lib.rs | 1 - src/test/run-pass/sepcomp-statics.rs | 2 +- src/test/run-pass/sepcomp-unwind.rs | 2 +- src/test/run-pass/seq-compare.rs | 1 - src/test/run-pass/shift-various-types.rs | 1 - src/test/run-pass/shift.rs | 1 - src/test/run-pass/signal-exit-status.rs | 12 +- src/test/run-pass/signed-shift-const-eval.rs | 1 - .../run-pass/sigpipe-should-be-ignored.rs | 1 - src/test/run-pass/simd-binop.rs | 1 - src/test/run-pass/simd-generics.rs | 1 - src/test/run-pass/simd-size-align.rs | 1 - src/test/run-pass/slice-2.rs | 1 - src/test/run-pass/slice-panic-1.rs | 1 - src/test/run-pass/slice-panic-2.rs | 1 - src/test/run-pass/slice.rs | 1 - src/test/run-pass/small-enum-range-edge.rs | 1 - src/test/run-pass/spawn-fn.rs | 9 +- src/test/run-pass/spawn-types.rs | 1 - src/test/run-pass/stable-addr-of.rs | 1 - .../run-pass/static-function-pointer-xc.rs | 1 - src/test/run-pass/static-function-pointer.rs | 1 - src/test/run-pass/static-impl.rs | 1 - ...tic-method-in-trait-with-tps-intracrate.rs | 1 - src/test/run-pass/static-method-xcrate.rs | 1 - src/test/run-pass/static-methods-in-traits.rs | 1 - src/test/run-pass/static-mut-foreign.rs | 1 - src/test/run-pass/static-mut-xc.rs | 1 - src/test/run-pass/str-multiline.rs | 1 - src/test/run-pass/string-escapes.rs | 1 - src/test/run-pass/struct-aliases-xcrate.rs | 1 - src/test/run-pass/struct-aliases.rs | 1 - .../struct-destructuring-cross-crate.rs | 1 - .../run-pass/struct-like-variant-match.rs | 1 - src/test/run-pass/struct-new-as-field-name.rs | 1 - src/test/run-pass/struct-order-of-eval-1.rs | 1 - src/test/run-pass/struct-order-of-eval-2.rs | 1 - src/test/run-pass/struct-order-of-eval-3.rs | 1 - src/test/run-pass/struct-order-of-eval-4.rs | 1 - src/test/run-pass/struct_variant_xc_match.rs | 1 - .../run-pass/supertrait-default-generics.rs | 1 - src/test/run-pass/swap-1.rs | 1 - src/test/run-pass/swap-2.rs | 1 - src/test/run-pass/syntax-extension-cfg.rs | 1 - src/test/run-pass/syntax-trait-polarity.rs | 6 +- src/test/run-pass/tag-align-dyn-u64.rs | 1 - src/test/run-pass/tag-align-dyn-variants.rs | 1 - src/test/run-pass/tag-align-u64.rs | 1 - src/test/run-pass/tag-variant-disr-val.rs | 1 - src/test/run-pass/tag.rs | 1 - src/test/run-pass/tail-direct.rs | 1 - src/test/run-pass/task-comm-0.rs | 3 +- src/test/run-pass/task-comm-1.rs | 2 +- src/test/run-pass/task-comm-10.rs | 4 +- src/test/run-pass/task-comm-11.rs | 3 +- src/test/run-pass/task-comm-12.rs | 2 +- src/test/run-pass/task-comm-13.rs | 2 +- src/test/run-pass/task-comm-14.rs | 2 +- src/test/run-pass/task-comm-15.rs | 3 +- src/test/run-pass/task-comm-17.rs | 2 +- src/test/run-pass/task-comm-3.rs | 2 +- src/test/run-pass/task-comm-5.rs | 1 - src/test/run-pass/task-comm-6.rs | 1 - src/test/run-pass/task-comm-7.rs | 14 +- src/test/run-pass/task-comm-9.rs | 2 +- src/test/run-pass/task-comm-chan-nil.rs | 1 - src/test/run-pass/task-life-0.rs | 2 +- src/test/run-pass/task-spawn-move-and-copy.rs | 5 +- src/test/run-pass/task-stderr.rs | 5 +- src/test/run-pass/tcp-accept-stress.rs | 88 - src/test/run-pass/tcp-connect-timeouts.rs | 76 - src/test/run-pass/tcp-stress.rs | 50 +- src/test/run-pass/tempfile.rs | 213 - src/test/run-pass/terminate-in-initializer.rs | 1 - src/test/run-pass/threads.rs | 2 +- src/test/run-pass/trait-bounds-basic.rs | 4 +- src/test/run-pass/trait-bounds-in-arc.rs | 9 +- .../trait-bounds-on-structs-and-enums.rs | 4 +- src/test/run-pass/trait-bounds-recursion.rs | 8 +- src/test/run-pass/trait-bounds.rs | 1 - .../trait-default-method-bound-subst.rs | 1 - .../trait-default-method-bound-subst2.rs | 1 - .../trait-default-method-bound-subst3.rs | 1 - .../trait-default-method-bound-subst4.rs | 1 - .../run-pass/trait-default-method-bound.rs | 1 - .../run-pass/trait-default-method-xc-2.rs | 1 - src/test/run-pass/trait-default-method-xc.rs | 1 - src/test/run-pass/trait-generic.rs | 1 - src/test/run-pass/trait-impl.rs | 1 - .../run-pass/trait-inheritance-auto-xc-2.rs | 1 - .../run-pass/trait-inheritance-auto-xc.rs | 1 - src/test/run-pass/trait-inheritance-auto.rs | 1 - .../trait-inheritance-call-bound-inherited.rs | 1 - ...trait-inheritance-call-bound-inherited2.rs | 1 - ...ritance-cast-without-call-to-supertrait.rs | 1 - src/test/run-pass/trait-inheritance-cast.rs | 1 - .../trait-inheritance-cross-trait-call-xc.rs | 1 - .../trait-inheritance-cross-trait-call.rs | 1 - .../run-pass/trait-inheritance-diamond.rs | 1 - .../trait-inheritance-multiple-inheritors.rs | 1 - .../trait-inheritance-multiple-params.rs | 1 - src/test/run-pass/trait-inheritance-num.rs | 11 +- src/test/run-pass/trait-inheritance-num0.rs | 5 +- src/test/run-pass/trait-inheritance-num1.rs | 7 +- src/test/run-pass/trait-inheritance-num2.rs | 9 +- src/test/run-pass/trait-inheritance-num3.rs | 10 +- src/test/run-pass/trait-inheritance-num5.rs | 14 +- .../trait-inheritance-overloading-xc-exe.rs | 1 - .../trait-inheritance-self-in-supertype.rs | 4 - src/test/run-pass/trait-inheritance-simple.rs | 1 - src/test/run-pass/trait-inheritance-static.rs | 1 - .../run-pass/trait-inheritance-static2.rs | 8 +- src/test/run-pass/trait-inheritance-subst.rs | 1 - src/test/run-pass/trait-inheritance-subst2.rs | 1 - .../run-pass/trait-inheritance-visibility.rs | 1 - src/test/run-pass/trait-inheritance2.rs | 1 - src/test/run-pass/trait-object-generics.rs | 1 - .../trait-object-with-lifetime-bound.rs | 1 - src/test/run-pass/trait-safety-ok-cc.rs | 1 - src/test/run-pass/trait-safety-ok.rs | 1 - .../traits-assoc-type-in-supertrait.rs | 1 - .../run-pass/traits-conditional-dispatch.rs | 5 +- .../run-pass/traits-conditional-model-fn.rs | 1 - .../run-pass/traits-default-method-macro.rs | 1 - .../traits-impl-object-overlap-issue-23853.rs | 27 + ...aits-multidispatch-infer-convert-target.rs | 1 - .../run-pass/traits-repeated-supertrait.rs | 1 - src/test/run-pass/trans-tag-static-padding.rs | 1 - src/test/run-pass/tup.rs | 1 - src/test/run-pass/tuple-index-fat-types.rs | 1 - src/test/run-pass/tuple-index.rs | 1 - src/test/run-pass/tydesc-name.rs | 1 - src/test/run-pass/type-id-higher-rank.rs | 1 - src/test/run-pass/type-namespace.rs | 1 - src/test/run-pass/type-sizes.rs | 1 - .../typeck-macro-interaction-issue-8852.rs | 1 - .../run-pass/typeck_type_placeholder_1.rs | 1 - src/test/run-pass/typeid-intrinsic.rs | 1 - src/test/run-pass/typestate-multi-decl.rs | 1 - src/test/run-pass/u32-decr.rs | 1 - src/test/run-pass/u8-incr-decr.rs | 1 - src/test/run-pass/u8-incr.rs | 1 - src/test/run-pass/ufcs-polymorphic-paths.rs | 17 +- src/test/run-pass/ufcs-trait-object.rs | 1 - .../run-pass/unboxed-closures-all-traits.rs | 1 - .../unboxed-closures-blanket-fn-mut.rs | 1 - .../run-pass/unboxed-closures-blanket-fn.rs | 1 - src/test/run-pass/unboxed-closures-by-ref.rs | 1 - .../unboxed-closures-call-fn-autoderef.rs | 1 - .../unboxed-closures-call-sugar-autoderef.rs | 1 - .../unboxed-closures-counter-not-moved.rs | 1 - .../run-pass/unboxed-closures-cross-crate.rs | 1 - src/test/run-pass/unboxed-closures-drop.rs | 1 - .../run-pass/unboxed-closures-extern-fn-hr.rs | 1 - .../run-pass/unboxed-closures-extern-fn.rs | 1 - ...unboxed-closures-fn-as-fnmut-and-fnonce.rs | 1 - .../unboxed-closures-fnmut-as-fnonce.rs | 1 - ...nfer-argument-types-from-expected-bound.rs | 10 +- ...rgument-types-from-expected-object-type.rs | 10 +- ...-with-bound-regions-from-expected-bound.rs | 10 +- ...oxed-closures-infer-fnmut-calling-fnmut.rs | 1 - .../unboxed-closures-infer-fnmut-move.rs | 1 - .../run-pass/unboxed-closures-infer-fnmut.rs | 1 - .../unboxed-closures-infer-fnonce-move.rs | 1 - .../run-pass/unboxed-closures-infer-fnonce.rs | 1 - .../run-pass/unboxed-closures-infer-kind.rs | 1 - .../unboxed-closures-infer-recursive-fn.rs | 1 - .../run-pass/unboxed-closures-infer-upvar.rs | 1 - .../run-pass/unboxed-closures-manual-impl.rs | 1 - ...ures-move-some-upvars-in-by-ref-closure.rs | 1 - src/test/run-pass/unboxed-closures-simple.rs | 1 - .../unboxed-closures-single-word-env.rs | 1 - .../run-pass/unboxed-closures-sugar-object.rs | 1 - .../unboxed-closures-unique-type-id.rs | 1 - src/test/run-pass/unfold-cross-crate.rs | 1 - src/test/run-pass/uniq-self-in-mut-slot.rs | 1 - src/test/run-pass/unique-assign-copy.rs | 1 - src/test/run-pass/unique-assign-drop.rs | 1 - src/test/run-pass/unique-assign-generic.rs | 1 - src/test/run-pass/unique-assign.rs | 1 - src/test/run-pass/unique-autoderef-field.rs | 1 - src/test/run-pass/unique-autoderef-index.rs | 1 - src/test/run-pass/unique-cmp.rs | 1 - src/test/run-pass/unique-decl-init-copy.rs | 1 - src/test/run-pass/unique-decl-init.rs | 1 - src/test/run-pass/unique-decl-move.rs | 1 - src/test/run-pass/unique-decl.rs | 1 - src/test/run-pass/unique-deref.rs | 1 - src/test/run-pass/unique-destructure.rs | 1 - src/test/run-pass/unique-fn-arg-move.rs | 1 - src/test/run-pass/unique-fn-arg-mut.rs | 1 - src/test/run-pass/unique-fn-arg.rs | 1 - src/test/run-pass/unique-fn-ret.rs | 1 - src/test/run-pass/unique-in-vec-copy.rs | 1 - src/test/run-pass/unique-in-vec.rs | 1 - src/test/run-pass/unique-kinds.rs | 1 - src/test/run-pass/unique-move-drop.rs | 1 - src/test/run-pass/unique-move-temp.rs | 1 - src/test/run-pass/unique-move.rs | 1 - src/test/run-pass/unique-mutable.rs | 1 - src/test/run-pass/unique-pat-2.rs | 1 - src/test/run-pass/unique-pat.rs | 1 - src/test/run-pass/unique-rec.rs | 1 - src/test/run-pass/unique-send-2.rs | 7 +- src/test/run-pass/unique-send.rs | 1 - src/test/run-pass/unique-swap.rs | 1 - .../run-pass/unit-like-struct-drop-run.rs | 1 - src/test/run-pass/unreachable-code-1.rs | 1 - src/test/run-pass/unreachable-code.rs | 1 - src/test/run-pass/unsafe-coercion.rs | 1 - .../run-pass/unsafe-pointer-assignability.rs | 1 - src/test/run-pass/unsized.rs | 20 +- src/test/run-pass/unsized3.rs | 1 - src/test/run-pass/unwind-unique.rs | 1 - src/test/run-pass/utf8_idents.rs | 2 - src/test/run-pass/variadic-ffi.rs | 1 - ...ariance-intersection-of-ref-and-opt-ref.rs | 1 - src/test/run-pass/variance-trait-matching.rs | 49 - src/test/run-pass/variance-vec-covariant.rs | 1 - src/test/run-pass/vec-dst.rs | 1 - src/test/run-pass/vec-fixed-length.rs | 1 - src/test/run-pass/vec-growth.rs | 1 - src/test/run-pass/vec-macro-repeat.rs | 1 - src/test/run-pass/vec-macro-rvalue-scope.rs | 1 - .../run-pass/vec-macro-with-trailing-comma.rs | 1 - src/test/run-pass/vec-matching-autoslice.rs | 1 - src/test/run-pass/vec-matching-fixed.rs | 1 - src/test/run-pass/vec-matching-fold.rs | 1 - src/test/run-pass/vec-matching.rs | 1 - src/test/run-pass/vec-slice-drop.rs | 1 - src/test/run-pass/vec-slice.rs | 1 - src/test/run-pass/vec-tail-matching.rs | 1 - src/test/run-pass/vec-to_str.rs | 1 - src/test/run-pass/vec.rs | 1 - src/test/run-pass/vector-sort-panic-safe.rs | 28 +- .../run-pass/wait-forked-but-failed-child.rs | 9 +- src/test/run-pass/where-for-self.rs | 8 +- src/test/run-pass/while-label.rs | 1 - src/test/run-pass/while-let.rs | 1 - src/test/run-pass/while-prelude-drop.rs | 2 - src/test/run-pass/writealias.rs | 1 - src/test/run-pass/x86stdcall2.rs | 2 + .../run-pass/xcrate-address-insignificant.rs | 1 - .../run-pass/zero-size-type-destructors.rs | 1 - .../run-pass/zero_sized_subslice_match.rs | 1 - .../lib.rs => rustdoc/assoc-types.rs} | 2 +- .../user.rs => rustdoc/default-impl.rs} | 11 +- src/test/rustdoc/extern-default-method.rs | 17 + .../bar.rs => rustdoc/extern-method.rs} | 11 +- src/test/rustdoc/ffi.rs | 22 + .../foo.rs => rustdoc/hidden-line.rs} | 4 +- src/test/rustdoc/inline-default-methods.rs | 19 + src/test/rustdoc/issue-13698.rs | 26 + src/test/rustdoc/issue-15169.rs | 13 + src/test/rustdoc/issue-15318-2.rs | 22 + src/test/rustdoc/issue-15318-3.rs | 15 + src/test/rustdoc/issue-15318.rs | 22 + src/test/rustdoc/issue-15347.rs | 15 + src/test/rustdoc/issue-16019.rs | 19 + src/test/rustdoc/issue-16265-1.rs | 18 + src/test/rustdoc/issue-16265-2.rs | 15 + src/test/rustdoc/issue-17476.rs | 21 + src/test/rustdoc/issue-18199.rs | 19 + src/test/rustdoc/issue-19055.rs | 30 + src/test/rustdoc/issue-20175.rs | 20 + src/test/rustdoc/issue-20646.rs | 36 + src/test/rustdoc/issue-20727-2.rs | 33 + src/test/rustdoc/issue-20727-3.rs | 34 + src/test/rustdoc/issue-20727-4.rs | 50 + src/test/rustdoc/issue-20727.rs | 34 + src/test/rustdoc/issue-21092.rs | 18 + src/test/rustdoc/issue-21474.rs | 21 + src/test/rustdoc/issue-21801.rs | 19 + src/test/rustdoc/issue-22025.rs | 16 + src/test/rustdoc/issue-22038.rs | 29 + src/test/rustdoc/issue-23106.rs | 17 + src/test/rustdoc/issue-23207.rs | 20 + src/test/rustdoc/issue-23511.rs | 24 + src/test/rustdoc/issue-23744.rs | 22 + .../lib.rs => rustdoc/must-use.rs} | 6 +- .../foo.rs => rustdoc/negative-impl.rs} | 8 +- .../foo.rs => rustdoc/recursion1.rs} | 0 .../foo2.rs => rustdoc/recursion2.rs} | 0 .../foo3.rs => rustdoc/recursion3.rs} | 0 .../index.rs => rustdoc/search-index.rs} | 0 .../rustdoc-smoke/foo.rs => rustdoc/smoke.rs} | 15 +- src/test/rustdoc/src-links.rs | 56 + src/test/rustdoc/src-links/mod.rs | 29 + .../foo.rs => rustdoc/viewpath-self.rs} | 2 + .../rustdoc-where/foo.rs => rustdoc/where.rs} | 2 + 1834 files changed, 21806 insertions(+), 51015 deletions(-) create mode 100644 src/compiletest/raise_fd_limit.rs create mode 100644 src/doc/trpl/academic-research.md delete mode 100644 src/doc/trpl/advanced-macros.md delete mode 100644 src/doc/trpl/advanced.md delete mode 100644 src/doc/trpl/arrays-vectors-and-slices.md create mode 100644 src/doc/trpl/attributes.md delete mode 100644 src/doc/trpl/basic.md create mode 100644 src/doc/trpl/casting-between-types.md rename src/doc/trpl/{plugins.md => compiler-plugins.md} (100%) delete mode 100644 src/doc/trpl/compound-data-types.md delete mode 100644 src/doc/trpl/conclusion.md create mode 100644 src/doc/trpl/conditional-compilation.md create mode 100644 src/doc/trpl/const.md create mode 100644 src/doc/trpl/debug-and-display.md create mode 100644 src/doc/trpl/deref-coercions.md create mode 100644 src/doc/trpl/drop.md create mode 100644 src/doc/trpl/effective-rust.md create mode 100644 src/doc/trpl/enums.md create mode 100644 src/doc/trpl/for-loops.md create mode 100644 src/doc/trpl/getting-started.md create mode 100644 src/doc/trpl/if-let.md delete mode 100644 src/doc/trpl/intermediate.md create mode 100644 src/doc/trpl/learn-rust.md create mode 100644 src/doc/trpl/lifetimes.md delete mode 100644 src/doc/trpl/looping.md delete mode 100644 src/doc/trpl/more-strings.md create mode 100644 src/doc/trpl/move-semantics.md create mode 100644 src/doc/trpl/mutability.md create mode 100644 src/doc/trpl/nightly-rust.md create mode 100644 src/doc/trpl/operators-and-overloading.md delete mode 100644 src/doc/trpl/pointers.md create mode 100644 src/doc/trpl/primitive-types.md create mode 100644 src/doc/trpl/references-and-borrowing.md create mode 100644 src/doc/trpl/slice-patterns.md create mode 100644 src/doc/trpl/static.md create mode 100644 src/doc/trpl/structs.md create mode 100644 src/doc/trpl/syntax-and-semantics.md create mode 100644 src/doc/trpl/the-stack-and-the-heap.md delete mode 100644 src/doc/trpl/tracing-macros.md rename src/doc/trpl/{static-and-dynamic-dispatch.md => trait-objects.md} (99%) create mode 100644 src/doc/trpl/tuple-structs.md create mode 100644 src/doc/trpl/type-aliases.md create mode 100644 src/doc/trpl/ufcs.md rename src/doc/trpl/{unsafe.md => unsafe-code.md} (99%) create mode 100644 src/doc/trpl/unsized-types.md delete mode 100644 src/doc/trpl/unstable.md create mode 100644 src/doc/trpl/vectors.md create mode 100644 src/doc/trpl/while-loops.md delete mode 100755 src/etc/rustup.sh create mode 100644 src/libbacktrace/ChangeLog.jit create mode 100644 src/libbacktrace/sort.c create mode 100644 src/libbacktrace/stest.c create mode 100644 src/libcoretest/fmt/float.rs create mode 100644 src/librustc/macros.rs create mode 100644 src/librustc/util/num.rs rename src/{libstd/sys/windows/udp.rs => librustc_borrowck/diagnostics.rs} (71%) create mode 100644 src/librustc_trans/trans/attributes.rs create mode 100644 src/librustc_trans/trans/declare.rs create mode 100644 src/librustc_typeck/check/cast.rs create mode 100644 src/librustdoc/clean/simplify.rs delete mode 100644 src/libstd/num/strconv.rs delete mode 100644 src/libstd/old_io/buffered.rs delete mode 100644 src/libstd/old_io/comm_adapters.rs delete mode 100644 src/libstd/old_io/extensions.rs delete mode 100644 src/libstd/old_io/fs.rs delete mode 100644 src/libstd/old_io/mem.rs delete mode 100644 src/libstd/old_io/mod.rs delete mode 100644 src/libstd/old_io/net/addrinfo.rs delete mode 100644 src/libstd/old_io/net/ip.rs delete mode 100644 src/libstd/old_io/net/mod.rs delete mode 100644 src/libstd/old_io/net/pipe.rs delete mode 100644 src/libstd/old_io/net/tcp.rs delete mode 100644 src/libstd/old_io/net/udp.rs delete mode 100644 src/libstd/old_io/pipe.rs delete mode 100644 src/libstd/old_io/process.rs delete mode 100644 src/libstd/old_io/result.rs delete mode 100644 src/libstd/old_io/stdio.rs delete mode 100644 src/libstd/old_io/tempfile.rs delete mode 100644 src/libstd/old_io/test.rs delete mode 100644 src/libstd/old_io/timer.rs delete mode 100644 src/libstd/old_io/util.rs delete mode 100644 src/libstd/old_path/mod.rs delete mode 100644 src/libstd/old_path/posix.rs delete mode 100644 src/libstd/old_path/windows.rs delete mode 100644 src/libstd/sys/common/net.rs rename src/libstd/{sync => sys/common}/poison.rs (99%) create mode 100644 src/libstd/sys/common/remutex.rs delete mode 100644 src/libstd/sys/unix/fs.rs delete mode 100644 src/libstd/sys/unix/pipe.rs delete mode 100644 src/libstd/sys/unix/process.rs delete mode 100644 src/libstd/sys/unix/tcp.rs delete mode 100644 src/libstd/sys/unix/timer.rs delete mode 100644 src/libstd/sys/unix/tty.rs delete mode 100644 src/libstd/sys/windows/fs.rs delete mode 100644 src/libstd/sys/windows/helper_signal.rs delete mode 100644 src/libstd/sys/windows/pipe.rs delete mode 100644 src/libstd/sys/windows/process.rs delete mode 100644 src/libstd/sys/windows/tcp.rs delete mode 100644 src/libstd/sys/windows/timer.rs delete mode 100644 src/libstd/sys/windows/tty.rs rename src/libstd/thread/{scoped.rs => scoped_tls.rs} (96%) delete mode 100644 src/libsyntax/ext/deriving/rand.rs create mode 100644 src/test/auxiliary/inline-default-methods.rs rename src/test/{run-make/rustdoc-extern-default-method/lib.rs => auxiliary/issue-13698.rs} (81%) create mode 100644 src/test/auxiliary/issue-15318.rs create mode 100644 src/test/auxiliary/issue-17476.rs create mode 100644 src/test/auxiliary/issue-20646.rs create mode 100644 src/test/auxiliary/issue-20727.rs create mode 100644 src/test/auxiliary/issue-21092.rs create mode 100644 src/test/auxiliary/issue-21801.rs create mode 100644 src/test/auxiliary/issue-22025.rs rename src/test/{compile-fail/issue-22426-2.rs => auxiliary/issue-23207-1.rs} (90%) create mode 100644 src/test/auxiliary/issue-23207-2.rs create mode 100644 src/test/auxiliary/llvm_pass_plugin.rs rename src/test/{run-make/rustdoc-default-impl/foo.rs => auxiliary/rustdoc-default-impl.rs} (94%) rename src/test/{run-make/rustdoc-extern-default-method/ext.rs => auxiliary/rustdoc-extern-default-method.rs} (100%) rename src/test/{run-make/rustdoc-extern-method/foo.rs => auxiliary/rustdoc-extern-method.rs} (100%) rename src/test/{run-make/rustdoc-ffi/lib.rs => auxiliary/rustdoc-ffi.rs} (100%) create mode 100644 src/test/compile-fail/associated-types-no-suitable-supertrait-2.rs create mode 100644 src/test/compile-fail/borrowck-escaping-closure-error-1.rs create mode 100644 src/test/compile-fail/borrowck-escaping-closure-error-2.rs create mode 100644 src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs create mode 100644 src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs create mode 100644 src/test/compile-fail/coherence-impl-trait-for-trait.rs create mode 100644 src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs create mode 100644 src/test/compile-fail/dupe-symbols-1.rs create mode 100644 src/test/compile-fail/dupe-symbols-2.rs create mode 100644 src/test/compile-fail/dupe-symbols-3.rs create mode 100644 src/test/compile-fail/dupe-symbols-4.rs create mode 100644 src/test/compile-fail/dupe-symbols-5.rs create mode 100644 src/test/compile-fail/dupe-symbols-6.rs create mode 100644 src/test/compile-fail/dupe-symbols-7.rs create mode 100644 src/test/compile-fail/enum-to-float-cast-2.rs create mode 100644 src/test/compile-fail/fat-ptr-cast.rs create mode 100644 src/test/compile-fail/impl-unused-rps-in-assoc-type.rs rename src/test/{run-pass/issue-19121.rs => compile-fail/issue-19482.rs} (75%) create mode 100644 src/test/compile-fail/issue-20772.rs create mode 100644 src/test/compile-fail/issue-20939.rs create mode 100644 src/test/compile-fail/issue-21950.rs create mode 100644 src/test/compile-fail/issue-22034.rs create mode 100644 src/test/compile-fail/issue-22289.rs create mode 100644 src/test/compile-fail/issue-22370.rs create mode 100644 src/test/compile-fail/issue-22384.rs create mode 100644 src/test/compile-fail/issue-22560.rs create mode 100644 src/test/compile-fail/issue-22886.rs create mode 100644 src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs create mode 100644 src/test/compile-fail/issue-23729.rs create mode 100644 src/test/compile-fail/issue-23827.rs create mode 100644 src/test/compile-fail/issue-24036.rs create mode 100644 src/test/compile-fail/issue-24267-flow-exit.rs create mode 100644 src/test/compile-fail/issue-24356.rs create mode 100644 src/test/compile-fail/issue-24365.rs create mode 100644 src/test/compile-fail/loops-reject-duplicate-labels-2.rs create mode 100644 src/test/compile-fail/loops-reject-duplicate-labels.rs create mode 100644 src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs create mode 100644 src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs create mode 100644 src/test/compile-fail/macro-backtrace-invalid-internals.rs create mode 100644 src/test/compile-fail/macro-backtrace-nested.rs create mode 100644 src/test/compile-fail/macro-backtrace-println.rs create mode 100644 src/test/compile-fail/old-suffixes-are-really-forbidden.rs create mode 100644 src/test/compile-fail/self-impl.rs create mode 100644 src/test/compile-fail/stability-attribute-non-staged.rs create mode 100644 src/test/compile-fail/struct-base-wrong-type-2.rs create mode 100644 src/test/compile-fail/variadic-ffi-3.rs create mode 100644 src/test/parse-fail/issue-24197.rs create mode 100644 src/test/parse-fail/issue-24375.rs rename src/test/{compile-fail/issue-22426-1.rs => parse-fail/pat-lt-bracket-1.rs} (88%) create mode 100644 src/test/parse-fail/pat-lt-bracket-2.rs rename src/test/{compile-fail/issue-22426-3.rs => parse-fail/pat-lt-bracket-3.rs} (89%) create mode 100644 src/test/parse-fail/pat-lt-bracket-4.rs create mode 100644 src/test/parse-fail/pat-lt-bracket-5.rs create mode 100644 src/test/parse-fail/pat-lt-bracket-6.rs create mode 100644 src/test/parse-fail/pat-lt-bracket-7.rs create mode 100644 src/test/parse-fail/pat-ranges-1.rs create mode 100644 src/test/parse-fail/pat-ranges-2.rs create mode 100644 src/test/parse-fail/pat-ranges-3.rs create mode 100644 src/test/parse-fail/pat-ranges-4.rs create mode 100644 src/test/parse-fail/wrong-escape-of-curly-braces.rs create mode 100644 src/test/run-fail/diverging-closure.rs create mode 100644 src/test/run-fail/overflowing-neg.rs create mode 100644 src/test/run-make/include_bytes_deps/Makefile create mode 100644 src/test/run-make/include_bytes_deps/input.bin create mode 100644 src/test/run-make/include_bytes_deps/input.txt rename src/{libstd/sys/unix/udp.rs => test/run-make/include_bytes_deps/main.rs} (68%) create mode 100644 src/test/run-make/issue-24445/Makefile rename src/test/run-make/{rustdoc-default-impl/bar.rs => issue-24445/foo.c} (87%) create mode 100644 src/test/run-make/issue-24445/foo.rs delete mode 100644 src/test/run-make/rustdoc-assoc-types/Makefile delete mode 100644 src/test/run-make/rustdoc-default-impl/Makefile delete mode 100644 src/test/run-make/rustdoc-extern-default-method/Makefile delete mode 100644 src/test/run-make/rustdoc-extern-method/Makefile delete mode 100644 src/test/run-make/rustdoc-ffi/Makefile delete mode 100644 src/test/run-make/rustdoc-hidden-line/Makefile delete mode 100644 src/test/run-make/rustdoc-must-use/Makefile delete mode 100644 src/test/run-make/rustdoc-negative-impl/Makefile delete mode 100644 src/test/run-make/rustdoc-recursion/Makefile delete mode 100644 src/test/run-make/rustdoc-search-index/Makefile delete mode 100644 src/test/run-make/rustdoc-smoke/Makefile delete mode 100644 src/test/run-make/rustdoc-src-links/Makefile delete mode 100644 src/test/run-make/rustdoc-src-links/foo.rs delete mode 100644 src/test/run-make/rustdoc-src-links/qux/mod.rs delete mode 100644 src/test/run-make/rustdoc-viewpath-self/Makefile delete mode 100644 src/test/run-make/rustdoc-where/Makefile rename src/test/{run-pass => run-pass-fulldeps}/issue-15149.rs (85%) create mode 100644 src/test/run-pass-fulldeps/llvm-pass-plugin.rs create mode 100644 src/test/run-pass/associated-types-projection-to-unrelated-trait.rs create mode 100644 src/test/run-pass/atomic-print.rs delete mode 100644 src/test/run-pass/capturing-logging.rs rename src/test/{compile-fail => run-pass}/coherence-subtyping.rs (94%) delete mode 100644 src/test/run-pass/deriving-primitive.rs delete mode 100644 src/test/run-pass/deriving-rand.rs create mode 100644 src/test/run-pass/discriminant_value.rs delete mode 100644 src/test/run-pass/exponential-notation.rs create mode 100644 src/test/run-pass/fds-are-cloexec.rs create mode 100644 src/test/run-pass/fmt-pointer-trait.rs delete mode 100644 src/test/run-pass/issue-12684.rs create mode 100644 src/test/run-pass/issue-15523-big.rs create mode 100644 src/test/run-pass/issue-15523.rs create mode 100644 src/test/run-pass/issue-16602-1.rs create mode 100644 src/test/run-pass/issue-16602-2.rs create mode 100644 src/test/run-pass/issue-16602-3.rs rename src/test/run-pass/{issue-18619.rs => issue-19097.rs} (74%) create mode 100644 src/test/run-pass/issue-21291.rs create mode 100644 src/test/run-pass/issue-21400.rs create mode 100644 src/test/run-pass/issue-21486.rs create mode 100644 src/test/run-pass/issue-22546.rs create mode 100644 src/test/run-pass/issue-23338-ensure-param-drop-order.rs create mode 100644 src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs create mode 100644 src/test/run-pass/issue-24161.rs create mode 100644 src/test/run-pass/issue-24434.rs create mode 100644 src/test/run-pass/issue24353.rs create mode 100644 src/test/run-pass/macro-nested_stmt_macros.rs create mode 100644 src/test/run-pass/macro-stmt_macro_in_expr_macro.rs create mode 100644 src/test/run-pass/pat-ranges.rs delete mode 100644 src/test/run-pass/tcp-accept-stress.rs delete mode 100644 src/test/run-pass/tcp-connect-timeouts.rs delete mode 100644 src/test/run-pass/tempfile.rs create mode 100644 src/test/run-pass/traits-impl-object-overlap-issue-23853.rs delete mode 100644 src/test/run-pass/variance-trait-matching.rs rename src/test/{run-make/rustdoc-assoc-types/lib.rs => rustdoc/assoc-types.rs} (95%) rename src/test/{run-make/rustdoc-ffi/user.rs => rustdoc/default-impl.rs} (76%) create mode 100644 src/test/rustdoc/extern-default-method.rs rename src/test/{run-make/rustdoc-extern-method/bar.rs => rustdoc/extern-method.rs} (74%) create mode 100644 src/test/rustdoc/ffi.rs rename src/test/{run-make/rustdoc-hidden-line/foo.rs => rustdoc/hidden-line.rs} (94%) create mode 100644 src/test/rustdoc/inline-default-methods.rs create mode 100644 src/test/rustdoc/issue-13698.rs create mode 100644 src/test/rustdoc/issue-15169.rs create mode 100644 src/test/rustdoc/issue-15318-2.rs create mode 100644 src/test/rustdoc/issue-15318-3.rs create mode 100644 src/test/rustdoc/issue-15318.rs create mode 100644 src/test/rustdoc/issue-15347.rs create mode 100644 src/test/rustdoc/issue-16019.rs create mode 100644 src/test/rustdoc/issue-16265-1.rs create mode 100644 src/test/rustdoc/issue-16265-2.rs create mode 100644 src/test/rustdoc/issue-17476.rs create mode 100644 src/test/rustdoc/issue-18199.rs create mode 100644 src/test/rustdoc/issue-19055.rs create mode 100644 src/test/rustdoc/issue-20175.rs create mode 100644 src/test/rustdoc/issue-20646.rs create mode 100644 src/test/rustdoc/issue-20727-2.rs create mode 100644 src/test/rustdoc/issue-20727-3.rs create mode 100644 src/test/rustdoc/issue-20727-4.rs create mode 100644 src/test/rustdoc/issue-20727.rs create mode 100644 src/test/rustdoc/issue-21092.rs create mode 100644 src/test/rustdoc/issue-21474.rs create mode 100644 src/test/rustdoc/issue-21801.rs create mode 100644 src/test/rustdoc/issue-22025.rs create mode 100644 src/test/rustdoc/issue-22038.rs create mode 100644 src/test/rustdoc/issue-23106.rs create mode 100644 src/test/rustdoc/issue-23207.rs create mode 100644 src/test/rustdoc/issue-23511.rs create mode 100644 src/test/rustdoc/issue-23744.rs rename src/test/{run-make/rustdoc-must-use/lib.rs => rustdoc/must-use.rs} (81%) rename src/test/{run-make/rustdoc-negative-impl/foo.rs => rustdoc/negative-impl.rs} (63%) rename src/test/{run-make/rustdoc-recursion/foo.rs => rustdoc/recursion1.rs} (100%) rename src/test/{run-make/rustdoc-recursion/foo2.rs => rustdoc/recursion2.rs} (100%) rename src/test/{run-make/rustdoc-recursion/foo3.rs => rustdoc/recursion3.rs} (100%) rename src/test/{run-make/rustdoc-search-index/index.rs => rustdoc/search-index.rs} (100%) rename src/test/{run-make/rustdoc-smoke/foo.rs => rustdoc/smoke.rs} (74%) create mode 100644 src/test/rustdoc/src-links.rs create mode 100644 src/test/rustdoc/src-links/mod.rs rename src/test/{run-make/rustdoc-viewpath-self/foo.rs => rustdoc/viewpath-self.rs} (97%) rename src/test/{run-make/rustdoc-where/foo.rs => rustdoc/where.rs} (98%) diff --git a/AUTHORS.txt b/AUTHORS.txt index 4109797a55..83d8d9ef0c 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -9,17 +9,19 @@ Aaron Todd Aaron Turon Aaron Weiss Adam Bozanich +Adam Jacob Adam Roben Adam Szkoda +Adenilson Cavalcanti Adolfo Ochagavía Adrien Brault Adrien Tétar -Ahmed Charles Ahmed Charles Aidan Cully Aidan Hobson Sayers Akos Kiss Alan Andrade +Alan Cutter Alan Williams Aleksander Balicki Aleksandr Koshlo @@ -29,6 +31,8 @@ Alex Lyon Alex Rønne Petersen Alex Whitney Alexander Bliskovsky +Alexander Campbell +Alexander Chernyakhovsky Alexander Korolkov Alexander Light Alexander Stavonin @@ -41,6 +45,7 @@ Alfie John Ali Smesseim Alisdair Owens Aljaž "g5pw" Srebrnič +Amol Mundayoor Amy Unger Anders Kaseorg Andre Arko @@ -56,6 +61,7 @@ Andrew Cann Andrew Chin Andrew Dunham Andrew Gallant +Andrew Hobden Andrew Paseltiner Andrew Poelstra Andrew Wagner @@ -110,6 +116,8 @@ Brendan McLoughlin Brendan Zabarauskas Brett Cannon Brian Anderson +Brian Brooks +Brian Campbell Brian Dawn Brian J Brennan Brian J. Burg @@ -122,6 +130,8 @@ Cadence Marseille Caitlin Potter Cam Jackson Cameron Zwarich +Camille Roussel +Camille TJHOA CarVac Carl Lerche Carl-Anton Ingmarsson @@ -132,6 +142,8 @@ Carter Hinsley Carter Tazio Schonwald Caspar Krieger Chase Southwood +Ches Martin +Chloe <5paceToast@users.noreply.github.com> Chris Double Chris Morgan Chris Nixon @@ -158,7 +170,9 @@ Corey Farwell Corey Ford Corey Richardson Cristi Burcă +Cristian Kubis DJUrsus +Dabo Ross Damian Gryski Damien Grassart Damien Radtke @@ -167,6 +181,8 @@ Dan Albert Dan Burkert Dan Connolly Dan Luu +Dan Schatzberg +Dan W. <1danwade@gmail.com> Dan Yang Daniel Brooks Daniel Fagnan @@ -174,6 +190,7 @@ Daniel Farina Daniel Griffen Daniel Grunwald Daniel Hofstetter +Daniel Lobato García Daniel Luz Daniel MacDougall Daniel Micay @@ -183,17 +200,23 @@ Daniel Ralston Daniel Rosenwasser Daniel Ursache Dogariu Daniil Smirnov +Darin Morrison +Darrell Hamilton Dave Herman Dave Hodder +Dave Huseby David Creswick David Forsythe David Halperin +David King David Klein +David Mally David Manescu David Rajchenbach-Teller David Renshaw David Vazgenovich Shakaryan Davis Silverman +Denis Defreyne Derecho Derek Chiang Derek Guenther @@ -214,10 +237,12 @@ Do Nhat Minh Dominik Inführ Donovan Preston Douglas Young +Drew Crawford Drew Willcoxon Duane Edwards Duncan Regan Dylan Braithwaite +Dylan Ede Dzmitry Malyshau Earl St Sauver Eduard Bopp @@ -230,12 +255,14 @@ Elantsev Serj Elliott Slaughter Elly Fong-Jones Emanuel Rylke +Emeliov Dmitrii Eric Allen Eric Biggers Eric Holk Eric Holmes Eric Kidd Eric Martin +Eric Platon Eric Reed Erick Rivas Erick Tryzelaar @@ -268,6 +295,7 @@ Florian Wilkens Florian Zeitz Francisco Souza Franklin Chen +FuGangqiang Gabriel Gareth Daniel Smith Garrett Heel @@ -279,8 +307,10 @@ Geoffrey Thomas Geoffroy Couprie George Papanikolaou Georges Dubus +Germano Gabbianelli Gil Cottle Gioele Barabucci +GlacJAY Gleb Kozyrev Glenn Willen Gonçalo Cabrita <_@gmcabrita.com> @@ -303,9 +333,11 @@ Herman J. Radtke III HeroesGrave Hong Chulju Honza Strnad +Huachao Huang Hugo Jobling Hugo van der Wijst Huon Wilson +Hyeon Kim Ian Connolly Ian D. Bollinger Ian Daniher @@ -318,12 +350,14 @@ Isaac Aggrey Isaac Dupree Ivan Enderlin Ivan Petkov +Ivan Radanov Ivanov Ivan Ukhov Ivano Coppola J. J. Weber J.C. Moyer JONNALAGADDA Srinivas JP Sugarbroad +JP-Ellis Jack Heizer Jack Moffitt Jacob Edelman @@ -338,6 +372,7 @@ Jake Kerr Jake Scott Jakub Bukaj Jakub Wieczorek +Jakub Vrána James Deng James Hurst James Lal @@ -359,6 +394,7 @@ Jason Toffaletti Jauhien Piatlicki Jay Anderson Jay True +Jeaye Jed Davis Jed Estep Jeff Balogh @@ -375,29 +411,36 @@ Jesse Jones Jesse Luehrs Jesse Ray Jesse Ruderman -Jihyun Yu +Jessy Diamond Exum +Jihyeok Seo +Jihyun Yu Jim Apple Jim Blandy Jim Radford Jimmie Elvenmark Jimmy Lu Jimmy Zelinskie +Jiří Stránský Joe Pletcher Joe Schafer Johannes Hoff Johannes Löthberg Johannes Muenzel +Johannes Oertel John Albietz John Barker John Clements +John Ericson John Fresco John Gallagher John Hodge John Kåre Alsaker John Kleint +John Kåre Alsaker John Louis Walker John Schmidt John Simon +John Zhang Jon Haddad Jon Morton Jonas Hietala @@ -407,6 +450,7 @@ Jonathan Reem Jonathan S Jonathan Sternberg Joonas Javanainen +Jordan Woehr Jordi Boggiano Jorge Aparicio Jorge Israel Peña @@ -423,16 +467,17 @@ Joshua Wise Joshua Yanovski Julia Evans Julian Orth +Julian Viereck Junseok Lee Junyoung Cho JustAPerson Justin Noah Jyun-Yan You Kang Seonghoon -Kang Seonghoon Kasey Carrothers Keegan McAllister Kelly Wilson +Kelvin Ly Ken Tossell KernelJ Keshav Kini @@ -442,6 +487,7 @@ Kevin Butler Kevin Cantu Kevin Mehall Kevin Murphy +Kevin Rauwolf Kevin Walter Kevin Yap Kiet Tran @@ -459,6 +505,8 @@ Lee Wondong LemmingAvalanche Lennart Kudling Leo Testard +Leonids Maslovs +Liam Monahan Liigo Zhuang Lindsey Kuper Lionel Flandrin @@ -495,6 +543,7 @@ Mathijs van de Nes Matt Brubeck Matt Carberry Matt Coffin +Matt Cox Matt McPherrin Matt Murphy Matt Roche @@ -532,6 +581,7 @@ Michael Sullivan Michael Williams Michael Woerister Michael Zhou +Michał Krasnoborski Mick Koch Mickaël Delahaye Mihnea Dobrescu-Balaur @@ -559,7 +609,9 @@ Nathaniel Theis Neil Pankey Nelson Chen NiccosSystem +Nicholas Nicholas Bishop +Nicholas Mazzuca Nick Cameron Nick Desaulniers Nick Howell @@ -579,8 +631,10 @@ Oliver Schneider Olivier Saut Olle Jonsson Or Brostovski +Or Neeman Oren Hazi Orpheus Lummis +Orphée Lafond-Lummis P1start Pablo Brasero Palmer Cox @@ -590,8 +644,11 @@ Patrick Reisert Patrick Walton Patrick Yevsukov Patrik Kårlin +Paul ADENOT Paul Collier +Paul Collins Paul Crowley +Paul Osborne Paul Stansifer Paul Woolcock Pavel Panchekha @@ -602,6 +659,7 @@ Peter Atashian Peter Elmers Peter Hull Peter Marheine +Peter Minten Peter Schuller Peter Williams Peter Zotov @@ -620,14 +678,17 @@ Potpourri Pradeep Kumar Prudhvi Krishna Surapaneni Pyfisch +Pyry Kontio Pythoner6 Q.P.Liu Rafael Ávila de Espíndola +Rahul Horé Ralph Bodenner Ralph Giles Ramkumar Ramachandra Randati Raphael Catolino +Raphael Nestler Raphael Speyer Raul Gutierrez S Ray Clanan @@ -637,6 +698,7 @@ Renato Riccieri Santos Zannon Renato Zannon Reuben Morais Ricardo M. Correia +Ricardo Martins Rich Lane Richard Diamond Richo Healey @@ -663,10 +725,13 @@ Russell Ruud van Asseldonk Ryan Levick Ryan Mulligan +Ryan Prichard +Ryan Riginding Ryan Scheel Ryman Rüdiger Sonderfeld S Pradeep Kumar +Sae-bom Kim Salem Talha Samuel Chase Samuel Neves @@ -678,6 +743,7 @@ Santiago Rodriguez Saurabh Anand Scott Jenkins Scott Lawrence +Scott Olson Sean Chalmers Sean Collins Sean Gillespie @@ -730,10 +796,13 @@ Tamir Duberstein Taras Shpot Taylor Hutchison Ted Horst +Tero Hänninen Thad Guidry Thiago Carvalho +Thiago Pontes Thomas Backman Thomas Daede +Tiago Nobrega Till Hoeppner Tim Brooks Tim Chevalier @@ -760,6 +829,7 @@ Toni Cárdenas Tony Young Torsten Weber Travis Watkins +Trent Nadeau Trent Ogren Trinick Tristan Storch @@ -769,9 +839,9 @@ TyOverby Tycho Sci Tyler Bindon Tyler Thrailkill -U-NOV2010\eugals Ulrik Sverdrup Ulysse Carion +User Jyyou Utkarsh Kukreti Uwe Dauernheim Vadim Chugunov @@ -797,6 +867,7 @@ Wade Mealing Wangshan Lu WebeWizard Wendell Smith +Wesley Wiser Will William Ting Willson Mock @@ -817,12 +888,16 @@ Zack Slayton Zbigniew Siciarz Ziad Hatahet Zooko Wilcox-O'Hearn +adridu59 aochagavia areski arturo auREAX +awlnx +aydin.kim b1nd bachm +bcoopers blackbeam blake2-ppc bluss @@ -835,6 +910,7 @@ comex crhino dan@daramos.com darkf +defuz dgoon donkopotamus eliovir @@ -845,6 +921,7 @@ fort free-Runner g3xzh gamazeps +gareth gentlefolk gifnksm hansjorg @@ -860,6 +937,8 @@ joaoxsouls jrincayc juxiliary jxv +kgv +kjpgit klutzy korenchkin kud1ing @@ -868,6 +947,7 @@ kvark kwantam lpy lucy +lummax lyuts m-r-r madmalik @@ -882,20 +962,26 @@ mrec musitdev nathan dotz nham +niftynif noam novalis +nsf +nwin oli-obk olivren osa1 posixphreak qwitwa +ray glover reedlepee +reus rjz sevrak sheroze1123 smenardpw sp3d startling +tav th0114nd theptrk thiagopnts @@ -911,3 +997,5 @@ xales zofrex zslayton zzmp +Łukasz Niemier +克雷 diff --git a/Makefile.in b/Makefile.in index e7ad2aec7b..ec5c099372 100644 --- a/Makefile.in +++ b/Makefile.in @@ -159,6 +159,13 @@ # # Admittedly this is a little convoluted. # +# If you find yourself working on the make infrastructure itself, and trying to +# find the value of a given variable after expansion, you can use: +# +# make print-VARIABLE_NAME +# +# To extract it +# # # diff --git a/configure b/configure index ca73c1cf8b..18fef58893 100755 --- a/configure +++ b/configure @@ -192,6 +192,7 @@ valopt_core() { then local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') local V="CFG_${UOP}" + local V_PROVIDED="${V}_PROVIDED" eval $V="$DEFAULT" for arg in $CFG_CONFIGURE_ARGS do @@ -199,6 +200,7 @@ valopt_core() { then val=$(echo "$arg" | cut -f2 -d=) eval $V=$val + eval $V_PROVIDED=1 fi done if [ "$SAVE" = "save" ] @@ -247,8 +249,10 @@ opt_core() { if [ $DEFAULT -eq 0 ] then FLAG="enable" + DEFAULT_FLAG="disable" else FLAG="disable" + DEFAULT_FLAG="enable" DOC="don't $DOC" fi @@ -261,11 +265,19 @@ opt_core() { OP=$(echo $OP | tr 'a-z-' 'A-Z_') FLAG=$(echo $FLAG | tr 'a-z' 'A-Z') local V="CFG_${FLAG}_${OP}" + local V_PROVIDED="CFG_${FLAG}_${OP}_PROVIDED" eval $V=1 + eval $V_PROVIDED=1 if [ "$SAVE" = "save" ] then putvar $V fi + elif [ "$arg" = "--${DEFAULT_FLAG}-${OP}" ] + then + OP=$(echo $OP | tr 'a-z-' 'A-Z_') + DEFAULT_FLAG=$(echo $DEFAULT_FLAG | tr 'a-z' 'A-Z') + local V_PROVIDED="CFG_${DEFAULT_FLAG}_${OP}_PROVIDED" + eval $V_PROVIDED=1 fi done else @@ -523,31 +535,35 @@ fi BOOL_OPTIONS="" VAL_OPTIONS="" +opt debug 0 "debug mode" opt valgrind 0 "run tests with valgrind (memcheck by default)" opt helgrind 0 "run tests with helgrind instead of memcheck" opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind" opt docs 1 "build standard library documentation" opt compiler-docs 0 "build compiler documentation" -opt optimize 1 "build optimized rust code" -opt optimize-cxx 1 "build optimized C++ code" -opt optimize-llvm 1 "build optimized LLVM" opt optimize-tests 1 "build tests with optimizations" opt libcpp 1 "build with llvm with libc++ instead of libstdc++ when using clang" -opt llvm-assertions 1 "build LLVM with assertions" -opt debug 1 "build with extra debug fun" +opt llvm-assertions 0 "build LLVM with assertions" +opt debug-assertions 0 "build with debugging assertions" opt fast-make 0 "use .gitmodules as timestamp for submodule deps" opt ccache 0 "invoke gcc/clang via ccache to reuse object files between builds" opt local-rust 0 "use an installed rustc rather than downloading a snapshot" opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM" opt rpath 0 "build rpaths into rustc itself" -opt nightly 0 "build nightly packages" -opt verify-install 1 "verify installed binaries work" # This is used by the automation to produce single-target nightlies opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" -opt jemalloc 1 "build liballoc with jemalloc" opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway" +# Optimization and debugging options. These may be overridden by the release channel, etc. +opt_nosave optimize 1 "build optimized rust code" +opt_nosave optimize-cxx 1 "build optimized C++ code" +opt_nosave optimize-llvm 1 "build optimized LLVM" +opt_nosave llvm-assertions 0 "build LLVM with assertions" +opt_nosave debug-assertions 0 "build with debugging assertions" +opt_nosave debuginfo 0 "build with debugger metadata" +opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill" + valopt localstatedir "/var/lib" "local state directory" valopt sysconfdir "/etc" "install system configuration files" @@ -557,18 +573,19 @@ valopt llvm-root "" "set LLVM root" 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 release-channel "dev" "the name of the release channel to build" # Many of these are saved below during the "writing configuration" step # (others are conditionally saved). opt_nosave manage-submodules 1 "let the build manage the git submodules" opt_nosave clang 0 "prefer clang to gcc for building the runtime" +opt_nosave jemalloc 1 "build liballoc with jemalloc" valopt_nosave prefix "/usr/local" "set installation prefix" valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary" valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples" valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples" valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" -valopt_nosave release-channel "dev" "the name of the release channel to build" # Temporarily support old triples until buildbots get updated CFG_BUILD=$(to_llvm_triple $CFG_BUILD) @@ -612,22 +629,40 @@ fi step_msg "validating $CFG_SELF args" validate_opt -# Validate the release channel +# Validate the release channel, and configure options case "$CFG_RELEASE_CHANNEL" in - (dev | nightly | beta | stable) + nightly ) + msg "overriding settings for $CFG_RELEASE_CHANNEL" + CFG_ENABLE_LLVM_ASSERTIONS=1 ;; - (*) + dev | beta | stable) + ;; + *) err "release channel must be 'dev', 'nightly', 'beta' or 'stable'" ;; esac -# Continue supporting the old --enable-nightly flag to transition the bots -# XXX Remove me -if [ ! -z "$CFG_ENABLE_NIGHTLY" ] -then - CFG_RELEASE_CHANNEL=nightly +# Adjust perf and debug options for debug mode +if [ -n "$CFG_ENABLE_DEBUG" ]; then + msg "debug mode enabled, setting performance options" + if [ -z "$CFG_ENABLE_OPTIMIZE_PROVIDED" ]; then + msg "optimization not explicitly enabled, disabling optimization" + CFG_DISABLE_OPTIMIZE=1 + CFG_DISABLE_OPTIMIZE_CXX=1 + fi + CFG_ENABLE_LLVM_ASSERTIONS=1 + CFG_ENABLE_DEBUG_ASSERTIONS=1 + CFG_ENABLE_DEBUG_JEMALLOC=1 fi -putvar CFG_RELEASE_CHANNEL + +# OK, now write the debugging options +if [ -n "$CFG_DISABLE_OPTIMIZE" ]; then putvar CFG_DISABLE_OPTIMIZE; fi +if [ -n "$CFG_DISABLE_OPTIMIZE_CXX" ]; then putvar CFG_DISABLE_OPTIMIZE_CXX; fi +if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; fi +if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi +if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi +if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi # A magic value that allows the compiler to use unstable features # during the bootstrap even when doing so would normally be an error @@ -669,7 +704,6 @@ probe CFG_LD ld probe CFG_VALGRIND valgrind probe CFG_PERF perf probe CFG_ISCC iscc -probe CFG_JAVAC javac probe CFG_ANTLR4 antlr4 probe CFG_GRUN grun probe CFG_FLEX flex @@ -679,6 +713,14 @@ probe CFG_XELATEX xelatex probe CFG_GDB gdb 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" ] +then + probe CFG_JAVAC javac +fi + if [ ! -z "$CFG_GDB" ] then # Store GDB's version @@ -775,7 +817,7 @@ if [ $CFG_OSTYPE = unknown-bitrig ] then step_msg "on Bitrig, forcing use of clang, disabling jemalloc" CFG_ENABLE_CLANG=1 - CFG_ENABLE_JEMALLOC=0 + CFG_DISABLE_JEMALLOC=1 fi if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] @@ -828,6 +870,12 @@ then putvar CFG_ENABLE_CLANG fi +# Same with jemalloc. save the setting here. +if [ ! -z "$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" ] then step_msg "using custom LLVM at $CFG_LLVM_ROOT" @@ -1095,6 +1143,7 @@ do make_dir $h/test/debuginfo-gdb make_dir $h/test/debuginfo-lldb make_dir $h/test/codegen + make_dir $h/test/rustdoc done # Configure submodules @@ -1167,7 +1216,7 @@ do LLVM_DBG_OPTS="--enable-optimized" LLVM_INST_DIR=$LLVM_BUILD_DIR/Release fi - if [ ! -z "$CFG_DISABLE_LLVM_ASSERTIONS" ] + if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ] then LLVM_ASSERTION_OPTS="--disable-assertions" else @@ -1421,6 +1470,11 @@ move_if_changed config.tmp config.mk rm -f config.tmp touch config.stamp -step_msg "complete" +if [ -z "$CFG_ENABLE_DEBUG" ]; then + step_msg "configured in release mode. for development consider --enable-debug" +else + step_msg "complete" +fi + msg "run \`make help\`" msg diff --git a/mk/crates.mk b/mk/crates.mk index f594a6a19f..666d95b6d6 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -118,42 +118,13 @@ ONLY_RLIB_collections := 1 ONLY_RLIB_unicode := 1 ONLY_RLIB_rustc_bitflags := 1 +# Documented-by-default crates +DOC_CRATES := std alloc collections core libc unicode + ################################################################################ # You should not need to edit below this line ################################################################################ -# On channels where the only usable crate is std, only build documentation for -# std. This keeps distributions small and doesn't clutter up the API docs with -# confusing internal details from the crates behind the facade. -# -# (Disabled while cmr figures out how to change rustdoc to make reexports work -# slightly nicer. Otherwise, all cross-crate links to Vec will go to -# libcollections, breaking them, and [src] links for anything reexported will -# not work.) - -#ifeq ($(CFG_RELEASE_CHANNEL),stable) -#DOC_CRATES := std -#else -#ifeq ($(CFG_RELEASE_CHANNEL),beta) -#DOC_CRATES := std -#else -DOC_CRATES := $(filter-out rustc, \ - $(filter-out rustc_trans, \ - $(filter-out rustc_typeck, \ - $(filter-out rustc_borrowck, \ - $(filter-out rustc_resolve, \ - $(filter-out rustc_driver, \ - $(filter-out rustc_privacy, \ - $(filter-out rustc_lint, \ - $(filter-out log, \ - $(filter-out getopts, \ - $(filter-out syntax, $(CRATES)))))))))))) -#endif -#endif -COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \ - rustc_typeck rustc_driver syntax rustc_privacy \ - rustc_lint - # This macro creates some simple definitions for each crate being built, just # some munging of all of the parameters above. # diff --git a/mk/docs.mk b/mk/docs.mk index d297055ba9..d179d337fa 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -250,18 +250,20 @@ endif doc/$(1)/: $$(Q)mkdir -p $$@ -$(2) += doc/$(1)/index.html doc/$(1)/index.html: CFG_COMPILER_HOST_TRIPLE = $(CFG_TARGET) doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/ @$$(call E, rustdoc: $$@) $$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(CFG_BUILD)) \ - $$(RUSTDOC) --cfg dox --cfg stage2 $$< + $$(RUSTDOC) --cfg dox --cfg stage2 $$(RUSTFLAGS_$(1)) $$< endef -$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS))) +$(foreach crate,$(CRATES),$(eval $(call DEF_LIB_DOC,$(crate)))) +COMPILER_DOC_TARGETS := $(CRATES:%=doc/%/index.html) ifdef CFG_COMPILER_DOCS - $(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS))) + DOC_TARGETS += $(COMPILER_DOC_TARGETS) +else + DOC_TARGETS += $(DOC_CRATES:%=doc/%/index.html) endif ifdef CFG_DISABLE_DOCS diff --git a/mk/install.mk b/mk/install.mk index 8850cd7780..cabc97a1e4 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -8,12 +8,6 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. -ifdef CFG_DISABLE_VERIFY_INSTALL -MAYBE_DISABLE_VERIFY=--disable-verify -else -MAYBE_DISABLE_VERIFY= -endif - install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) # Build the dist as the original user @@ -22,9 +16,9 @@ else $(Q)$(MAKE) prepare_install endif ifeq ($(CFG_DISABLE_DOCS),) - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)" + $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" endif - $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" "$(MAYBE_DISABLE_VERIFY)" + $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)" # Remove tmp files because it's a decent amount of disk space $(Q)rm -R tmp/dist diff --git a/mk/main.mk b/mk/main.mk index b9f2cf1cce..c5b2fc8b95 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.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= +CFG_PRERELEASE_VERSION=.3 CFG_FILENAME_EXTRA=4e7c5e5c @@ -126,11 +126,16 @@ endif CFG_JEMALLOC_FLAGS += $(JEMALLOC_FLAGS) -ifdef CFG_DISABLE_DEBUG - CFG_RUSTC_FLAGS += --cfg ndebug -else - $(info cfg: enabling more debugging (CFG_ENABLE_DEBUG)) +ifdef CFG_ENABLE_DEBUG_ASSERTIONS + $(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS)) CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on +else + CFG_RUSTC_FLAGS += --cfg ndebug +endif + +ifdef CFG_ENABLE_DEBUGINFO + $(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO)) + CFG_RUSTC_FLAGS += -g endif ifdef SAVE_TEMPS diff --git a/mk/rt.mk b/mk/rt.mk index 527485c502..70abce8b46 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -143,6 +143,10 @@ else ifeq ($(findstring android, $(OSTYPE_$(1))), android) JEMALLOC_ARGS_$(1) := --disable-tls endif +ifdef CFG_ENABLE_DEBUG_JEMALLOC + JEMALLOC_ARGS_$(1) += --enable-debug --enable-fill +endif + ################################################################################ # jemalloc ################################################################################ diff --git a/mk/tests.mk b/mk/tests.mk index 48ebe4e540..a540d2bace 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -22,9 +22,11 @@ $(eval $(call RUST_CRATE,coretest)) DEPS_collectionstest := $(eval $(call RUST_CRATE,collectionstest)) -TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) collectionstest coretest +TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) \ + collectionstest coretest TEST_DOC_CRATES = $(DOC_CRATES) -TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\ +TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \ + rustc_trans rustc_lint,\ $(HOST_CRATES)) TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES) @@ -304,6 +306,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \ check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \ check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \ check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \ + check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \ check-stage$(1)-T-$(2)-H-$(3)-crates-exec \ check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \ check-stage$(1)-T-$(2)-H-$(3)-bench-exec \ @@ -471,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs) DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs) CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs) CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc) +RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs) # perf tests are the same as bench tests only they run under # a performance monitor. @@ -489,6 +493,7 @@ PRETTY_TESTS := $(PRETTY_RS) DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS) DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS) CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC) +RUSTDOCCK_TESTS := $(RUSTDOCCK_RS) CTEST_SRC_BASE_rpass = run-pass CTEST_BUILD_BASE_rpass = run-pass @@ -550,6 +555,11 @@ CTEST_BUILD_BASE_codegen = codegen CTEST_MODE_codegen = codegen CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL) +CTEST_SRC_BASE_rustdocck = rustdoc +CTEST_BUILD_BASE_rustdocck = rustdoc +CTEST_MODE_rustdocck = rustdoc +CTEST_RUNTOOL_rustdocck = $(CTEST_RUNTOOL) + # CTEST_DISABLE_$(TEST_GROUP), if set, will cause the test group to be # disabled and the associated message to be printed as a warning # during attempts to run those tests. @@ -618,12 +628,14 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + --rustdoc-path $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ --clang-path $(if $(CFG_CLANG),$(CFG_CLANG),clang) \ --llvm-bin-path $(CFG_LLVM_INST_DIR_$(CFG_BUILD))/bin \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ --target $(2) \ --host $(3) \ + --python $$(CFG_PYTHON) \ --gdb-version="$(CFG_GDB_VERSION)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ --android-cross-path=$(CFG_ANDROID_CROSS_PATH) \ @@ -660,6 +672,9 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \ $(S)src/etc/lldb_batchmode.py \ $(S)src/etc/lldb_rust_formatters.py CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS) +CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \ + $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \ + $(S)src/etc/htmldocck.py endef @@ -722,7 +737,8 @@ endif endef -CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail bench perf debuginfo-gdb debuginfo-lldb codegen +CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \ + bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck $(foreach host,$(CFG_HOST), \ $(eval $(foreach target,$(CFG_TARGET), \ @@ -890,6 +906,7 @@ TEST_GROUPS = \ bench \ perf \ rmake \ + rustdocck \ debuginfo-gdb \ debuginfo-lldb \ codegen \ diff --git a/mk/util.mk b/mk/util.mk index b419c0bbe8..3664236eab 100644 --- a/mk/util.mk +++ b/mk/util.mk @@ -16,4 +16,7 @@ else E = echo $(1) endif +print-%: + @echo $*=$($*) + S := $(CFG_SRC_DIR) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index fe556cecef..dcac32ccb8 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -23,7 +23,8 @@ pub enum Mode { Pretty, DebugInfoGdb, DebugInfoLldb, - Codegen + Codegen, + Rustdoc, } impl FromStr for Mode { @@ -39,6 +40,7 @@ impl FromStr for Mode { "debuginfo-lldb" => Ok(DebugInfoLldb), "debuginfo-gdb" => Ok(DebugInfoGdb), "codegen" => Ok(Codegen), + "rustdoc" => Ok(Rustdoc), _ => Err(()), } } @@ -56,6 +58,7 @@ impl fmt::Display for Mode { DebugInfoGdb => "debuginfo-gdb", DebugInfoLldb => "debuginfo-lldb", Codegen => "codegen", + Rustdoc => "rustdoc", }, f) } } @@ -71,6 +74,12 @@ pub struct Config { // The rustc executable pub rustc_path: PathBuf, + // The rustdoc executable + pub rustdoc_path: PathBuf, + + // The python executable + pub python: String, + // The clang executable pub clang_path: Option, diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index f00ff9bcbe..d014512666 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -12,16 +12,16 @@ #![feature(box_syntax)] #![feature(collections)] -#![feature(old_io)] #![feature(rustc_private)] -#![feature(unboxed_closures)] #![feature(std_misc)] #![feature(test)] #![feature(path_ext)] #![feature(str_char)] +#![feature(libc)] #![deny(warnings)] +extern crate libc; extern crate test; extern crate getopts; @@ -42,6 +42,7 @@ pub mod header; pub mod runtest; pub mod common; pub mod errors; +mod raise_fd_limit; pub fn main() { let config = parse_config(env::args().collect()); @@ -60,6 +61,8 @@ pub fn parse_config(args: Vec ) -> Config { vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"), reqopt("", "run-lib-path", "path to target shared libraries", "PATH"), reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"), + reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"), + reqopt("", "python", "path to python to use for doc tests", "PATH"), optopt("", "clang-path", "path to executable for codegen tests", "PATH"), optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"), optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"), @@ -128,6 +131,8 @@ pub fn parse_config(args: Vec ) -> Config { compile_lib_path: matches.opt_str("compile-lib-path").unwrap(), run_lib_path: matches.opt_str("run-lib-path").unwrap(), rustc_path: opt_path(matches, "rustc-path"), + rustdoc_path: opt_path(matches, "rustdoc-path"), + python: matches.opt_str("python").unwrap(), clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)), valgrind_path: matches.opt_str("valgrind-path"), force_valgrind: matches.opt_present("force-valgrind"), @@ -168,6 +173,7 @@ pub fn log_config(config: &Config) { logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path.display())); logv(c, format!("src_base: {:?}", config.src_base.display())); logv(c, format!("build_base: {:?}", config.build_base.display())); logv(c, format!("stage_id: {}", config.stage_id)); @@ -240,11 +246,7 @@ pub fn run_tests(config: &Config) { // sadly osx needs some file descriptor limits raised for running tests in // parallel (especially when we have lots and lots of child processes). // For context, see #8904 - #[allow(deprecated)] - fn raise_fd_limit() { - std::old_io::test::raise_fd_limit(); - } - raise_fd_limit(); + unsafe { raise_fd_limit::raise_fd_limit(); } // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary env::set_var("__COMPAT_LAYER", "RunAsInvoker"); @@ -366,7 +368,7 @@ pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::Test fn extract_gdb_version(full_version_line: Option) -> Option { match full_version_line { Some(ref full_version_line) - if full_version_line.trim().len() > 0 => { + if !full_version_line.trim().is_empty() => { let full_version_line = full_version_line.trim(); // used to be a regex "(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)" @@ -406,7 +408,7 @@ fn extract_lldb_version(full_version_line: Option) -> Option { match full_version_line { Some(ref full_version_line) - if full_version_line.trim().len() > 0 => { + if !full_version_line.trim().is_empty() => { let full_version_line = full_version_line.trim(); for (pos, l) in full_version_line.char_indices() { @@ -424,7 +426,7 @@ fn extract_lldb_version(full_version_line: Option) -> Option { let vers = full_version_line[pos + 5..].chars().take_while(|c| { c.is_digit(10) }).collect::(); - if vers.len() > 0 { return Some(vers) } + if !vers.is_empty() { return Some(vers) } } println!("Could not extract LLDB version from line '{}'", full_version_line); diff --git a/src/compiletest/raise_fd_limit.rs b/src/compiletest/raise_fd_limit.rs new file mode 100644 index 0000000000..89b9135558 --- /dev/null +++ b/src/compiletest/raise_fd_limit.rs @@ -0,0 +1,79 @@ +// 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. + +/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X +/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256 +/// ends up being far too low for our multithreaded scheduler testing, depending +/// on the number of cores available. +/// +/// This fixes issue #7772. +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[allow(non_camel_case_types)] +pub unsafe fn raise_fd_limit() { + use libc; + use std::cmp; + use std::io; + use std::mem::size_of_val; + use std::ptr::null_mut; + + type rlim_t = libc::uint64_t; + + #[repr(C)] + struct rlimit { + rlim_cur: rlim_t, + rlim_max: rlim_t + } + extern { + // name probably doesn't need to be mut, but the C function doesn't + // specify const + fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint, + oldp: *mut libc::c_void, oldlenp: *mut libc::size_t, + newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int; + fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int; + fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int; + } + static CTL_KERN: libc::c_int = 1; + static KERN_MAXFILESPERPROC: libc::c_int = 29; + static RLIMIT_NOFILE: libc::c_int = 8; + + // The strategy here is to fetch the current resource limits, read the + // kern.maxfilesperproc sysctl value, and bump the soft resource limit for + // maxfiles up to the sysctl value. + + // Fetch the kern.maxfilesperproc value + let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC]; + let mut maxfiles: libc::c_int = 0; + let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t; + if sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, + null_mut(), 0) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling sysctl: {}", err); + } + + // Fetch the current resource limits + let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0}; + if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling getrlimit: {}", err); + } + + // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard + // limit + rlim.rlim_cur = cmp::min(maxfiles as rlim_t, rlim.rlim_max); + + // Set our newly-increased resource limit + if setrlimit(RLIMIT_NOFILE, &rlim) != 0 { + let err = io::Error::last_os_error(); + panic!("raise_fd_limit: error calling setrlimit: {}", err); + } +} + +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +pub unsafe fn raise_fd_limit() {} diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 23267c3e93..8ae3639318 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -12,7 +12,7 @@ use self::TargetLocation::*; use common::Config; use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind}; -use common::{Codegen, DebugInfoLldb, DebugInfoGdb}; +use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc}; use errors; use header::TestProps; use header; @@ -29,7 +29,6 @@ use std::net::TcpStream; use std::path::{Path, PathBuf}; use std::process::{Command, Output, ExitStatus}; use std::str; -use std::time::Duration; use test::MetricMap; pub fn run(config: Config, testfile: &Path) { @@ -57,15 +56,16 @@ pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) { let props = header::load_props(&testfile); debug!("loaded props"); match config.mode { - CompileFail => run_cfail_test(&config, &props, &testfile), - ParseFail => run_cfail_test(&config, &props, &testfile), - RunFail => run_rfail_test(&config, &props, &testfile), - RunPass => run_rpass_test(&config, &props, &testfile), - RunPassValgrind => run_valgrind_test(&config, &props, &testfile), - Pretty => run_pretty_test(&config, &props, &testfile), - DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile), - DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile), - Codegen => run_codegen_test(&config, &props, &testfile, mm), + CompileFail => run_cfail_test(&config, &props, &testfile), + ParseFail => run_cfail_test(&config, &props, &testfile), + RunFail => run_rfail_test(&config, &props, &testfile), + RunPass => run_rpass_test(&config, &props, &testfile), + RunPassValgrind => run_valgrind_test(&config, &props, &testfile), + Pretty => run_pretty_test(&config, &props, &testfile), + DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile), + DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile), + Codegen => run_codegen_test(&config, &props, &testfile, mm), + Rustdoc => run_rustdoc_test(&config, &props, &testfile), } } @@ -382,7 +382,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { // write debugger script let mut script_str = String::with_capacity(2048); - script_str.push_str("set charset UTF-8\n"); + script_str.push_str(&format!("set charset {}\n", charset())); script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap())); script_str.push_str("target remote :5039\n"); script_str.push_str(&format!("set solib-search-path \ @@ -451,11 +451,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { .expect(&format!("failed to exec `{:?}`", config.adb_path)); loop { //waiting 1 second for gdbserver start - #[allow(deprecated)] - fn sleep() { - ::std::old_io::timer::sleep(Duration::milliseconds(1000)); - } - sleep(); + ::std::thread::sleep_ms(1000); if TcpStream::connect("127.0.0.1:5039").is_ok() { break } @@ -516,8 +512,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { .to_string(); // write debugger script let mut script_str = String::with_capacity(2048); - - script_str.push_str("set charset UTF-8\n"); + script_str.push_str(&format!("set charset {}\n", charset())); script_str.push_str("show version\n"); match config.gdb_version { @@ -726,32 +721,37 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes { // Prepare the lldb_batchmode which executes the debugger script let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py"); + cmd2procres(config, + test_executable, + Command::new(&config.python) + .arg(&lldb_script_path) + .arg(test_executable) + .arg(debugger_script) + .env("PYTHONPATH", + config.lldb_python_dir.as_ref().unwrap())) + } +} - let mut cmd = Command::new("python"); - cmd.arg(&lldb_script_path) - .arg(test_executable) - .arg(debugger_script) - .env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap()); - - let (status, out, err) = match cmd.output() { - Ok(Output { status, stdout, stderr }) => { - (status, - String::from_utf8(stdout).unwrap(), - String::from_utf8(stderr).unwrap()) - }, - Err(e) => { - fatal(&format!("Failed to setup Python process for \ - LLDB script: {}", e)) - } - }; +fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command) + -> ProcRes { + let (status, out, err) = match cmd.output() { + Ok(Output { status, stdout, stderr }) => { + (status, + String::from_utf8(stdout).unwrap(), + String::from_utf8(stderr).unwrap()) + }, + Err(e) => { + fatal(&format!("Failed to setup Python process for \ + LLDB script: {}", e)) + } + }; - dump_output(config, test_executable, &out, &err); - return ProcRes { - status: Status::Normal(status), - stdout: out, - stderr: err, - cmdline: format!("{:?}", cmd) - }; + dump_output(config, test_executable, &out, &err); + ProcRes { + status: Status::Normal(status), + stdout: out, + stderr: err, + cmdline: format!("{:?}", cmd) } } @@ -864,7 +864,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) } first = false; } - if !failed && rest.len() == 0 { + if !failed && rest.is_empty() { i += 1; } if i == num_check_lines { @@ -1158,6 +1158,26 @@ fn compile_test_(config: &Config, props: &TestProps, compose_and_run_compiler(config, props, testfile, args, None) } +fn document(config: &Config, props: &TestProps, + testfile: &Path, extra_args: &[String]) -> (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); + ensure_dir(&out_dir); + let mut args = vec!["-L".to_string(), + aux_dir.to_str().unwrap().to_string(), + "-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).into_iter()); + let args = ProcArgs { + prog: config.rustdoc_path.to_str().unwrap().to_string(), + args: args, + }; + (compose_and_run_compiler(config, props, testfile, args, None), out_dir) +} + fn exec_compiled_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes { @@ -1182,20 +1202,17 @@ fn exec_compiled_test(config: &Config, props: &TestProps, } } -fn compose_and_run_compiler( - config: &Config, - props: &TestProps, - testfile: &Path, - args: ProcArgs, - input: Option) -> ProcRes { - +fn compose_and_run_compiler(config: &Config, props: &TestProps, + testfile: &Path, args: ProcArgs, + input: Option) -> ProcRes { if !props.aux_builds.is_empty() { ensure_dir(&aux_output_dir_name(config, testfile)); } let aux_dir = aux_output_dir_name(config, testfile); // FIXME (#9639): This needs to handle non-utf8 paths - let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string()); + let extra_link_args = vec!["-L".to_string(), + aux_dir.to_str().unwrap().to_string()]; for rel_ab in &props.aux_builds { let abs_ab = config.aux_base.join(rel_ab); @@ -1331,8 +1348,8 @@ fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf { f } -fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) -> - ProcArgs { +fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) + -> ProcArgs { // If we've got another tool to run under (valgrind), // then split apart its command let mut args = split_maybe_args(&config.runtool); @@ -1645,7 +1662,7 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) { // codegen tests (vs. clang) fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf { - if suffix.len() == 0 { + if suffix.is_empty() { p.to_path_buf() } else { let mut stem = p.file_stem().unwrap().to_os_string(); @@ -1790,3 +1807,29 @@ fn run_codegen_test(config: &Config, props: &TestProps, (base_lines as f64) / (clang_lines as f64), 0.001); } + +fn charset() -> &'static str { + if cfg!(any(target_os = "bitrig", target_os = "freebsd")) { + "auto" + } else { + "UTF-8" + } +} + +fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) { + let (proc_res, out_dir) = document(config, props, testfile, &[]); + if !proc_res.status.success() { + fatal_proc_rec("rustdoc failed!", &proc_res); + } + let root = find_rust_src_root(config).unwrap(); + + let res = cmd2procres(config, + testfile, + Command::new(&config.python) + .arg(root.join("src/etc/htmldocck.py")) + .arg(out_dir) + .arg(testfile)); + if !res.status.success() { + fatal_proc_rec("htmldocck failed!", &res); + } +} diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index 3edbcbe62c..952416ac16 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -56,7 +56,7 @@ Types which are [`Sync`][sync] are thread-safe when multiple shared references to them are used concurrently. Types which are not `Sync` are not thread-safe, and thus when used in a global require unsafe code to use. -[sync]: core/kinds/trait.Sync.html +[sync]: core/marker/trait.Sync.html ### If mutable static items that implement `Sync` are safe, why is taking &mut SHARABLE unsafe? @@ -139,7 +139,7 @@ and explicitly calling the `clone` method. Making user-defined copy operators explicit surfaces the underlying complexity, forcing the developer to opt-in to potentially expensive operations. -[copy]: core/kinds/trait.Copy.html +[copy]: core/marker/trait.Copy.html [clone]: core/clone/trait.Clone.html ## No move constructors @@ -163,13 +163,18 @@ This is to make the language easier to parse for humans, especially in the face of higher-order functions. `fn foo(f: fn(int): int, fn(T): U): U` is not particularly easy to read. -## `let` is used to introduce variables +## Why is `let` used to introduce variables? -`let` not only defines variables, but can do pattern matching. One can also -redeclare immutable variables with `let`. This is useful to avoid unnecessary -`mut` annotations. An interesting historical note is that Rust comes, -syntactically, most closely from ML, which also uses `let` to introduce -bindings. +Instead of the term "variable", we use "variable bindings". The +simplest way for creating a binding is by using the `let` syntax. +Other ways include `if let`, `while let`, and `match`. Bindings also +exist in function argument positions. + +Bindings always happen in pattern matching positions, and it's also Rust's way +to declare mutability. One can also re-declare mutability of a binding in +pattern matching. This is useful to avoid unnecessary `mut` annotations. An +interesting historical note is that Rust comes, syntactically, most closely +from ML, which also uses `let` to introduce bindings. See also [a long thread][alt] on renaming `let mut` to `var`. diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 8238dd3a5b..f7bad3e402 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -42,10 +42,7 @@ Let the fact that this is an easily countable number be a warning. ## Does it run on Windows? -Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). Note that the Windows implementation currently has some limitations; in particular, the 64-bit build is [not fully supported yet][win64], and all executables created by rustc [depend on libgcc DLL at runtime][libgcc]. - -[win64]: https://github.com/rust-lang/rust/issues/1237 -[libgcc]: https://github.com/rust-lang/rust/issues/11782 +Yes. All development happens in lockstep on all 3 target platforms (using MinGW, not Cygwin). ## Is it OO? How do I do this thing I normally do in an OO language? diff --git a/src/doc/index.md b/src/doc/index.md index f6b0a18824..5a437e959b 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -15,6 +15,12 @@ Rust, its syntax, and its concepts. Upon completing the book, you'll be an intermediate Rust developer, and will have a good grasp of the fundamental ideas behind Rust. +[Rust By Example][rbe] was originally a community resource, but was then +donated to the Rust project. As the name implies, it teaches you Rust through a +series of small examples. + +[rbe]: http://rustbyexample.com/ + # Community & Getting Help If you need help with something, or just want to talk about Rust with others, @@ -76,17 +82,3 @@ 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. - -# External documentation - -*Note: While these are great resources for learning Rust, they may track a -particular version of Rust that is likely not exactly the same as that for -which this documentation was generated.* - -* [Rust by Example] - Short examples of common tasks in Rust (tracks the master - branch). -* [Rust for Rubyists] - The first community tutorial for Rust. Tracks the last - stable release. Not just for Ruby programmers. - -[Rust by Example]: http://rustbyexample.com/ -[Rust for Rubyists]: http://www.rustforrubyists.com/ diff --git a/src/doc/intro.md b/src/doc/intro.md index b711085ddb..48712d8d49 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -1,590 +1,5 @@ % A 30-minute Introduction to Rust -Rust is a modern systems programming language focusing on safety and speed. It -accomplishes these goals by being memory safe without using garbage collection. +This introduction is now deprecated. Please see [the introduction to the book][intro]. -This introduction will give you a rough idea of what Rust is like, eliding many -details. It does not require prior experience with systems programming, but you -may find the syntax easier if you've used a "curly brace" programming language -before, like C or JavaScript. The concepts are more important than the syntax, -so don't worry if you don't get every last detail: you can read [The -Rust Programming Language](book/index.html) to get a more complete explanation. - -Because this is about high-level concepts, you don't need to actually install -Rust to follow along. If you'd like to anyway, check out [the -homepage](http://rust-lang.org) for explanation. - -To show off Rust, let's talk about how easy it is to get started with Rust. -Then, we'll talk about Rust's most interesting feature, *ownership*, and -then discuss how it makes concurrency easier to reason about. Finally, -we'll talk about how Rust breaks down the perceived dichotomy between speed -and safety. - -# Tools - -Getting started on a new Rust project is incredibly easy, thanks to Rust's -package manager, [Cargo](http://crates.io). - -To start a new project with Cargo, use `cargo new`: - -```{bash} -$ cargo new hello_world --bin -``` - -We're passing `--bin` because we're making a binary program: if we -were making a library, we'd leave it off. - -Let's check out what Cargo has generated for us: - -```{bash} -$ cd hello_world -$ tree . -. -├── Cargo.toml -└── src - └── main.rs - -1 directory, 2 files -``` - -This is all we need to get started. First, let's check out `Cargo.toml`: - -```{toml} -[package] - -name = "hello_world" -version = "0.0.1" -authors = ["Your Name "] -``` - -This is called a *manifest*, and it contains all of the metadata that Cargo -needs to compile your project. - -Here's what's in `src/main.rs`: - -```{rust} -fn main() { - println!("Hello, world!"); -} -``` - -Cargo generated a "Hello World" for us. We'll talk more about the syntax here -later, but that's what Rust code looks like! Let's compile and run it: - -```{bash} -$ cargo run - Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world) - Running `target/hello_world` -Hello, world! -``` - -Using an external dependency in Rust is incredibly easy. You add a line to -your `Cargo.toml`: - -```{toml} -[package] - -name = "hello_world" -version = "0.0.1" -authors = ["Your Name "] - -[dependencies.semver] - -git = "https://github.com/rust-lang/semver.git" -``` - -You added the `semver` library, which parses version numbers and compares them -according to the [SemVer specification](http://semver.org/). - -Now, you can pull in that library using `extern crate` in -`main.rs`. - -```{rust,ignore} -extern crate semver; - -use semver::Version; - -fn main() { - assert!(Version::parse("1.2.3") == Ok(Version { - major: 1u64, - minor: 2u64, - patch: 3u64, - pre: vec!(), - build: vec!(), - })); - - println!("Versions compared successfully!"); -} -``` - -Again, we'll discuss the exact details of all of this syntax soon. For now, -let's compile and run it: - -```{bash} -$ cargo run - Updating git repository `https://github.com/rust-lang/semver.git` - Compiling semver v0.0.1 (https://github.com/rust-lang/semver.git#bf739419) - Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) - Running `target/hello_world` -Versions compared successfully! -``` - -Because we only specified a repository without a version, if someone else were -to try out our project at a later date, when `semver` was updated, they would -get a different, possibly incompatible version. To solve this problem, Cargo -produces a file, `Cargo.lock`, which records the versions of any dependencies. -This gives us repeatable builds. - -There is a lot more here, and this is a whirlwind tour, but you should feel -right at home if you've used tools like [Bundler](http://bundler.io/), -[npm](https://www.npmjs.org/), or [pip](https://pip.pypa.io/en/latest/). -There's no `Makefile`s or endless `autotools` output here. (Rust's tooling does -[play nice with external libraries written in those -tools](http://doc.crates.io/build-script.html), if you need to.) - -Enough about tools, let's talk code! - -# Ownership - -Rust's defining feature is "memory safety without garbage collection". Let's -take a moment to talk about what that means. *Memory safety* means that the -programming language eliminates certain kinds of bugs, such as [buffer -overflows](http://en.wikipedia.org/wiki/Buffer_overflow) and [dangling -pointers](http://en.wikipedia.org/wiki/Dangling_pointer). These problems occur -when you have unrestricted access to memory. As an example, here's some Ruby -code: - -```{ruby} -v = [] - -v.push("Hello") - -x = v[0] - -v.push("world") - -puts x -``` - -We make an array, `v`, and then call `push` on it. `push` is a method which -adds an element to the end of an array. - -Next, we make a new variable, `x`, that's equal to the first element of -the array. Simple, but this is where the "bug" will appear. - -Let's keep going. We then call `push` again, pushing "world" onto the -end of the array. `v` now is `["Hello", "world"]`. - -Finally, we print `x` with the `puts` method. This prints "Hello." - -All good? Let's go over a similar, but subtly different example, in C++: - -```{cpp} -#include -#include -#include - -int main() { - std::vector v; - - v.push_back("Hello"); - - std::string& x = v[0]; - - v.push_back("world"); - - std::cout << x; -} -``` - -It's a little more verbose due to the static typing, but it's almost the same -thing. We make a `std::vector` of `std::string`s, we call `push_back` (same as -`push`) on it, take a reference to the first element of the vector, call -`push_back` again, and then print out the reference. - -There's two big differences here: one, they're not _exactly_ the same thing, -and two... - -```{bash} -$ g++ hello.cpp -Wall -Werror -$ ./a.out -Segmentation fault (core dumped) -``` - -A crash! (Note that this is actually system-dependent. Because referring to an -invalid reference is undefined behavior, the compiler can do anything, -including the right thing!) Even though we compiled with flags to give us as -many warnings as possible, and to treat those warnings as errors, we got no -errors. When we ran the program, it crashed. - -Why does this happen? When we append to an array, its length changes. Since -its length changes, we may need to allocate more memory. In Ruby, this happens -as well, we just don't think about it very often. So why does the C++ version -segfault when we allocate more memory? - -The answer is that in the C++ version, `x` is a *reference* to the memory -location where the first element of the array is stored. But in Ruby, `x` is a -standalone value, not connected to the underlying array at all. Let's dig into -the details for a moment. Your program has access to memory, provided to it by -the operating system. Each location in memory has an address. So when we make -our vector, `v`, it's stored in a memory location somewhere: - -| location | name | value | -|----------|------|-------| -| 0x30 | v | | - -(Address numbers made up, and in hexadecimal. Those of you with deep C++ -knowledge, there are some simplifications going on here, like the lack of an -allocated length for the vector. This is an introduction.) - -When we push our first string onto the array, we allocate some memory, -and `v` refers to it: - -| location | name | value | -|----------|------|----------| -| 0x30 | v | 0x18 | -| 0x18 | | "Hello" | - -We then make a reference to that first element. A reference is a variable -that points to a memory location, so its value is the memory location of -the `"Hello"` string: - -| location | name | value | -|----------|------|----------| -| 0x30 | v | 0x18 | -| 0x18 | | "Hello" | -| 0x14 | x | 0x18 | - -When we push `"world"` onto the vector with `push_back`, there's no room: -we only allocated one element. So, we need to allocate two elements, -copy the `"Hello"` string over, and update the reference. Like this: - -| location | name | value | -|----------|------|----------| -| 0x30 | v | 0x08 | -| 0x18 | | GARBAGE | -| 0x14 | x | 0x18 | -| 0x08 | | "Hello" | -| 0x04 | | "world" | - -Note that `v` now refers to the new list, which has two elements. It's all -good. But our `x` didn't get updated! It still points at the old location, -which isn't valid anymore. In fact, [the documentation for `push_back` mentions -this](http://en.cppreference.com/w/cpp/container/vector/push_back): - -> If the new `size()` is greater than `capacity()` then all iterators and -> references (including the past-the-end iterator) are invalidated. - -Finding where these iterators and references are is a difficult problem, and -even in this simple case, `g++` can't help us here. While the bug is obvious in -this case, in real code, it can be difficult to track down the source of the -error. - -Before we talk about this solution, why didn't our Ruby code have this problem? -The semantics are a little more complicated, and explaining Ruby's internals is -out of the scope of a guide to Rust. But in a nutshell, Ruby's garbage -collector keeps track of references, and makes sure that everything works as -you might expect. This comes at an efficiency cost, and the internals are more -complex. If you'd really like to dig into the details, [this -article](http://patshaughnessy.net/2012/1/18/seeing-double-how-ruby-shares-string-values) -can give you more information. - -Garbage collection is a valid approach to memory safety, but Rust chooses a -different path. Let's examine what the Rust version of this looks like: - -```{rust,ignore} -fn main() { - let mut v = vec![]; - - v.push("Hello"); - - let x = &v[0]; - - v.push("world"); - - println!("{}", x); -} -``` - -This looks like a bit of both: fewer type annotations, but we do create new -variables with `let`. The method name is `push`, some other stuff is different, -but it's pretty close. So what happens when we compile this code? Does Rust -print `"Hello"`, or does Rust crash? - -Neither. It refuses to compile: - -```bash -$ cargo run - Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world) -main.rs:8:5: 8:6 error: cannot borrow `v` as mutable because it is also borrowed as immutable -main.rs:8 v.push("world"); - ^ -main.rs:6:14: 6:15 note: previous borrow of `v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `v` until the borrow ends -main.rs:6 let x = &v[0]; - ^ -main.rs:11:2: 11:2 note: previous borrow ends here -main.rs:1 fn main() { -... -main.rs:11 } - ^ -error: aborting due to previous error -``` - -When we try to mutate the array by `push`ing it the second time, Rust throws -an error. It says that we "cannot borrow v as mutable because it is also -borrowed as immutable." What does it mean by "borrowed"? - -In Rust, the type system encodes the notion of *ownership*. The variable `v` -is an *owner* of the vector. When we make a reference to `v`, we let that -variable (in this case, `x`) *borrow* it for a while. Just like if you own a -book, and you lend it to me, I'm borrowing the book. - -So, when I try to modify the vector with the second call to `push`, I need -to be owning it. But `x` is borrowing it. You can't modify something that -you've lent to someone. And so Rust throws an error. - -So how do we fix this problem? Well, we can make a copy of the element: - - -```{rust} -fn main() { - let mut v = vec![]; - - v.push("Hello"); - - let x = v[0].clone(); - - v.push("world"); - - println!("{}", x); -} -``` - -Note the addition of `clone()`. This creates a copy of the element, leaving -the original untouched. Now, we no longer have two references to the same -memory, and so the compiler is happy. Let's give that a try: - -```{bash} -$ cargo run - Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world) - Running `target/hello_world` -Hello -``` - -Same result. Now, making a copy can be inefficient, so this solution may not be -acceptable. There are other ways to get around this problem, but this is a toy -example, and because we're in an introduction, we'll leave that for later. - -The point is, the Rust compiler and its notion of ownership has saved us from a -bug that would crash the program. We've achieved safety, at compile time, -without needing to rely on a garbage collector to handle our memory. - -# Concurrency - -Rust's ownership model can help in other ways, as well. For example, take -concurrency. Concurrency is a big topic, and an important one for any modern -programming language. Let's take a look at how ownership can help you write -safe concurrent programs. - -Here's an example of a concurrent Rust program: - -```{rust} -use std::thread; - -fn main() { - let guards: Vec<_> = (0..10).map(|_| { - thread::scoped(|| { - println!("Hello, world!"); - }) - }).collect(); -} -``` - -This program creates ten threads, which all print `Hello, world!`. The `scoped` -function takes one argument, a closure, indicated by the double bars `||`. This -closure is executed in a new thread created by `scoped`. The method is called -`scoped` because it returns a 'join guard', which will automatically join the -child thread when it goes out of scope. Because we `collect` these guards into -a `Vec`, and that vector goes out of scope at the end of our program, our -program will wait for every thread to finish before finishing. - -One common form of problem in concurrent programs is a *data race*. -This occurs when two different threads attempt to access the same -location in memory in a non-synchronized way, where at least one of -them is a write. If one thread is attempting to read, and one thread -is attempting to write, you cannot be sure that your data will not be -corrupted. Note the first half of that requirement: two threads that -attempt to access the same location in memory. Rust's ownership model -can track which pointers own which memory locations, which solves this -problem. - -Let's see an example. This Rust code will not compile: - -```{rust,ignore} -use std::thread; - -fn main() { - let mut numbers = vec![1, 2, 3]; - - let guards: Vec<_> = (0..3).map(|i| { - thread::scoped(move || { - numbers[i] += 1; - println!("numbers[{}] is {}", i, numbers[i]); - }) - }).collect(); -} -``` - -It gives us this error: - -```text -7:25: 10:6 error: cannot move out of captured outer variable in an `FnMut` closure -7 thread::scoped(move || { -8 numbers[i] += 1; -9 println!("numbers[{}] is {}", i, numbers[i]); -10 }) -error: aborting due to previous error -``` - -This is a little confusing because there are two closures here: the one passed -to `map`, and the one passed to `thread::scoped`. In this case, the closure for -`thread::scoped` is attempting to reference `numbers`, a `Vec`. This -closure is a `FnOnce` closure, as that’s what `thread::scoped` takes as an -argument. `FnOnce` closures take ownership of their environment. That’s fine, -but there’s one detail: because of `map`, we’re going to make three of these -closures. And since all three try to take ownership of `numbers`, that would be -a problem. That’s what it means by ‘cannot move out of captured outer -variable’: our `thread::scoped` closure wants to take ownership, and it can’t, -because the closure for `map` won’t let it. - -What to do here? Rust has two types that helps us: `Arc` and `Mutex`. -*Arc* stands for "atomically reference counted". In other words, an Arc will -keep track of the number of references to something, and not free the -associated resource until the count is zero. The *atomic* portion refers to an -Arc's usage of concurrency primitives to atomically update the count, making it -safe across threads. If we use an Arc, we can have our three references. But, -an Arc does not allow mutable borrows of the data it holds, and we want to -modify what we're sharing. In this case, we can use a `Mutex` inside of our -Arc. A Mutex will synchronize our accesses, so that we can ensure that our -mutation doesn't cause a data race. - -Here's what using an Arc with a Mutex looks like: - -```{rust} -use std::thread; -use std::sync::{Arc,Mutex}; - -fn main() { - let numbers = Arc::new(Mutex::new(vec![1, 2, 3])); - - let guards: Vec<_> = (0..3).map(|i| { - let number = numbers.clone(); - thread::scoped(move || { - let mut array = number.lock().unwrap(); - array[i] += 1; - println!("numbers[{}] is {}", i, array[i]); - }) - }).collect(); -} -``` - -We first have to `use` the appropriate library, and then we wrap our vector in -an Arc with the call to `Arc::new()`. Inside of the loop, we make a new -reference to the Arc with the `clone()` method. This will increment the -reference count. When each new `numbers` variable binding goes out of scope, it -will decrement the count. The `lock()` call will return us a reference to the -value inside the Mutex, and block any other calls to `lock()` until said -reference goes out of scope. - -We can compile and run this program without error, and in fact, see the -non-deterministic aspect: - -```{shell} -$ cargo run - Compiling hello_world v0.0.1 (file:///Users/you/src/hello_world) - Running `target/hello_world` -numbers[1] is 3 -numbers[0] is 2 -numbers[2] is 4 -$ cargo run - Running `target/hello_world` -numbers[2] is 4 -numbers[1] is 3 -numbers[0] is 2 -``` - -Each time, we can get a slightly different output because the threads are not -guaranteed to run in any set order. If you get the same order every time it is -because each of these threads are very small and complete too fast for their -indeterminate behavior to surface. - -The important part here is that the Rust compiler was able to use ownership to -give us assurance _at compile time_ that we weren't doing something incorrect -with regards to concurrency. In order to share ownership, we were forced to be -explicit and use a mechanism to ensure that it would be properly handled. - -# Safety _and_ Speed - -Safety and speed are always presented as a continuum. At one end of the spectrum, -you have maximum speed, but no safety. On the other end, you have absolute safety -with no speed. Rust seeks to break out of this paradigm by introducing safety at -compile time, ensuring that you haven't done anything wrong, while compiling to -the same low-level code you'd expect without the safety. - -As an example, Rust's ownership system is _entirely_ at compile time. The -safety check that makes this an error about moved values: - -```{rust,ignore} -use std::thread; - -fn main() { - let numbers = vec![1, 2, 3]; - - let guards: Vec<_> = (0..3).map(|i| { - thread::scoped(move || { - println!("{}", numbers[i]); - }) - }).collect(); -} -``` - -carries no runtime penalty. And while some of Rust's safety features do have -a run-time cost, there's often a way to write your code in such a way that -you can remove it. As an example, this is a poor way to iterate through -a vector: - -```{rust} -let vec = vec![1, 2, 3]; - -for i in 0..vec.len() { - println!("{}", vec[i]); -} -``` - -The reason is that the access of `vec[i]` does bounds checking, to ensure -that we don't try to access an invalid index. However, we can remove this -while retaining safety. The answer is iterators: - -```{rust} -let vec = vec![1, 2, 3]; - -for x in &vec { - println!("{}", x); -} -``` - -This version uses an iterator that yields each element of the vector in turn. -Because we have a reference to the element, rather than the whole vector itself, -there's no array access bounds to check. - -# Learning More - -I hope that this taste of Rust has given you an idea if Rust is the right -language for you. We talked about Rust's tooling, how encoding ownership into -the type system helps you find bugs, how Rust can help you write correct -concurrent code, and how you don't have to pay a speed cost for much of this -safety. - -To continue your Rustic education, read [The Rust Programming -Language](book/index.html) for a more in-depth exploration of Rust's syntax and -concepts. +[intro]: book/README.html diff --git a/src/doc/reference.md b/src/doc/reference.md index cc90a69fd2..0ed23dae9b 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3788,7 +3788,7 @@ its type parameters are types: ```ignore fn map(f: |A| -> B, xs: &[A]) -> Vec { - if xs.len() == 0 { + if xs.is_empty() { return vec![]; } let first: B = f(xs[0].clone()); diff --git a/src/doc/style/testing/unit.md b/src/doc/style/testing/unit.md index 813660d8fd..dbbe9fc3ac 100644 --- a/src/doc/style/testing/unit.md +++ b/src/doc/style/testing/unit.md @@ -1,10 +1,10 @@ % Unit testing -Unit tests should live in a `test` submodule at the bottom of the module they -test. Mark the `test` submodule with `#[cfg(test)]` so it is only compiled when +Unit tests should live in a `tests` submodule at the bottom of the module they +test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when testing. -The `test` module should contain: +The `tests` module should contain: * Imports needed only for testing. * Functions marked with `#[test]` striving for full coverage of the parent module's @@ -17,7 +17,7 @@ For example: // Excerpt from std::str #[cfg(test)] -mod test { +mod tests { #[test] fn test_eq() { assert!((eq(&"".to_owned(), &"".to_owned()))); diff --git a/src/doc/trpl/README.md b/src/doc/trpl/README.md index 4a866d6224..8d3a6ec398 100644 --- a/src/doc/trpl/README.md +++ b/src/doc/trpl/README.md @@ -1,39 +1,192 @@ % The Rust Programming Language -Welcome! This book will teach you about [the Rust Programming -Language](http://www.rust-lang.org/). Rust is a modern systems programming -language focusing on safety and speed. It accomplishes these goals by being -memory safe without using garbage collection. +Welcome! This book will teach you about the [Rust Programming Language][rust]. +Rust is a systems programming language focused on three goals: safety, speed, +and concurrency. It maintains these goals without having a garbage collector, +making it a useful language for a number of use cases other languages aren’t +good at: embedding in other languages, programs with specific space and time +requirements, and writing low-level code, like device drivers and operating +systems. It improves on current languages targeting this space by having a +number of compile-time safety checks that produce no runtime overhead, while +eliminating all data races. Rust also aims to achieve ‘zero-cost abstrations’ +even though some of these abstractions feel like those of a high-level +language. Even then, Rust still allows precise control like a low-level +language would. -"The Rust Programming Language" is split into three sections, which you can -navigate through the menu on the left. +[rust]: http://rust-lang.org -

Basics

+“The Rust Programming Language” is split into seven sections. This introduction +is the first. After this: -This section is a linear introduction to the basic syntax and semantics of -Rust. It has individual sections on each part of Rust's syntax. +* [Getting started][gs] - Set up your computer for Rust development. +* [Learn Rust][lr] - Learn Rust programming through small projects. +* [Effective Rust][er] - Higher-level concepts for writing excellent Rust code. +* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks. +* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet. +* [Glossary][gl] - A reference of terms used in the book. -After reading "Basics," you will have a good foundation to learn more about -Rust, and can write very simple programs. +[gs]: getting-started.html +[lr]: learn-rust.html +[er]: effective-rust.html +[ss]: syntax-and-semantics.html +[nr]: nightly-rust.html +[gl]: glossary.html -

Intermediate

+After reading this introduction, you’ll want to dive into either ‘Learn Rust’ +or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you +want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to +start small, and learn a single concept thoroughly before moving onto the next. +Copious cross-linking connects these parts together. -This section contains individual chapters, which are self-contained. They focus -on specific topics, and can be read in any order. +## A brief introduction to Rust -After reading "Intermediate," you will have a solid understanding of Rust, -and will be able to understand most Rust code and write more complex programs. +Is Rust a language you might be interested in? Let’s examine a few small code +samples to show off a few of its strengths. -

Advanced

+The main concept that makes Rust unique is called ‘ownership’. Consider this +small example: -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on the most complex features, +```rust +fn main() { + let mut x = vec!["Hello", "world"]; +} +``` -

Unstable

+This program makes a [variable binding][var] named `x`. The value of this +binding is a `Vec`, a ‘vector’, that we create through a [macro][macro] +defined in the standard library. This macro is called `vec`, and we invoke +macros with a `!`. This follows a general principle of Rust: make things +explicit. Macros can do significantly more complicated things than function +calls, and so they’re visually distinct. The `!` also helps with parsing, +making tooling easier to write, which is also important. -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. +We used `mut` to make `x` mutable: bindings are immutable by default in Rust. +We’ll be mutating this vector later in the example. -This chapter contains things that are only available on the nightly channel of -Rust. +It’s also worth noting that we didn’t need a type annotation here: while Rust +is statically typed, we didn’t need to explicitly annotate the type. Rust has +type inference to balance out the power of static typing with the verbosity of +annotating types. + +Rust prefers stack allocation to heap allocation: `x` is placed directly on the +stack. However, the `Vec` type allocates space for the elements of the +vector on the heap. If you’re not familiar with this distinction, you can +ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems +programming language, Rust gives you the ability to control how your memory is +allocated, but when we’re getting started, it’s less of a big deal. + +[var]: variable-bindings.html +[macro]: macros.html +[heap]: the-stack-and-the-heap.html + +Earlier, we mentioned that ‘ownership’ is the key new concept in Rust. In Rust +parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of +scope, the vector’s memory will be de-allocated. This is done deterministically +by the Rust compiler, rather than through a mechanism such as a garbage +collector. In other words, in Rust, you don’t call functions like `malloc` and +`free` yourself: the compiler statically determines when you need to allocate +or deallocate memory, and inserts those calls itself. To err is to be human, +but compilers never forget. + +Let’s add another line to our example: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = &x[0]; +} +``` + +We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to +the first element of the vector. Rust’s references are similar to pointers in +other languages, but with additional compile-time safety checks. References +interact with the ownership system by [‘borrowing’][borrowing] what they point +to, rather than owning it. The difference is, when the reference goes out of +scope, it will not deallocate the underlying memory. If it did, we’d +de-allocate twice, which is bad! + +[borrowing]: references-and-borrowing.html + +Let’s add a third line. It looks innocent enough, but causes a compiler error: + +```rust,ignore +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = &x[0]; + + x.push("foo"); +} +``` + +`push` is a method on vectors that appends another element to the end of the +vector. When we try to compile this program, we get an error: + +```text +error: cannot borrow `x` as mutable because it is also borrowed as immutable + x.push(4); + ^ +note: previous borrow of `x` occurs here; the immutable borrow prevents +subsequent moves or mutable borrows of `x` until the borrow ends + let y = &x[0]; + ^ +note: previous borrow ends here +fn main() { + +} +^ +``` + +Whew! The Rust compiler gives quite detailed errors at times, and this is one +of those times. As the error explains, while we made our binding mutable, we +still cannot call `push`. This is because we already have a reference to an +element of the vector, `y`. Mutating something while another reference exists +is dangerous, because we may invalidate the reference. In this specific case, +when we create the vector, we may have only allocated space for three elements. +Adding a fourth would mean allocating a new chunk of memory for all those elements, +copying the old values over, and updating the internal pointer to that memory. +That all works just fine. The problem is that `y` wouldn’t get updated, and so +we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in +this case, and so the compiler has caught this for us. + +So how do we solve this problem? There are two approaches we can take. The first +is making a copy rather than using a reference: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + let y = x[0].clone(); + + x.push("foo"); +} +``` + +Rust has [move semantics][move] by default, so if we want to make a copy of some +data, we call the `clone()` method. In this example, `y` is no longer a reference +to the vector stored in `x`, but a copy of its first element, `"hello"`. Now +that we don’t have a reference, our `push()` works just fine. + +[move]: move-semantics.html + +If we truly want a reference, we need the other option: ensure that our reference +goes out of scope before we try to do the mutation. That looks like this: + +```rust +fn main() { + let mut x = vec!["Hello", "world"]; + + { + let y = &x[0]; + } + + x.push("foo"); +} +``` + +We created an inner scope with an additional set of curly braces. `y` will go out of +scope before we call `push()`, and so we’re all good. + +This concept of ownership isn’t just good for preventing danging pointers, but an +entire set of related problems, like iterator invalidation, concurrency, and more. diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index 11e62aff42..f2d1666048 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -1,42 +1,62 @@ # Summary -* [The Basics](basic.md) +* [Getting Started](getting-started.md) * [Installing Rust](installing-rust.md) * [Hello, world!](hello-world.md) * [Hello, Cargo!](hello-cargo.md) +* [Learn Rust](learn-rust.md) +* [Effective Rust](effective-rust.md) + * [The Stack and the Heap](the-stack-and-the-heap.md) + * [Debug and Display](debug-and-display.md) + * [Testing](testing.md) + * [Documentation](documentation.md) + * [Iterators](iterators.md) + * [Concurrency](concurrency.md) + * [Error Handling](error-handling.md) + * [FFI](ffi.md) + * [Deref coercions](deref-coercions.md) +* [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) - * [If](if.md) * [Functions](functions.md) + * [Primitive Types](primitive-types.md) * [Comments](comments.md) - * [Compound Data Types](compound-data-types.md) - * [Match](match.md) - * [Looping](looping.md) - * [Strings](strings.md) - * [Arrays, Vectors, and Slices](arrays-vectors-and-slices.md) -* [Intermediate Rust](intermediate.md) - * [Crates and Modules](crates-and-modules.md) - * [Testing](testing.md) - * [Pointers](pointers.md) + * [if](if.md) + * [for loops](for-loops.md) + * [while loops](while-loops.md) * [Ownership](ownership.md) - * [More Strings](more-strings.md) + * [References and Borrowing](references-and-borrowing.md) + * [Lifetimes](lifetimes.md) + * [Mutability](mutability.md) + * [Move semantics](move-semantics.md) + * [Enums](enums.md) + * [Match](match.md) * [Patterns](patterns.md) + * [Structs](structs.md) * [Method Syntax](method-syntax.md) - * [Associated Types](associated-types.md) - * [Closures](closures.md) - * [Iterators](iterators.md) - * [Generics](generics.md) + * [Drop](drop.md) + * [Vectors](vectors.md) + * [Strings](strings.md) * [Traits](traits.md) - * [Static and Dynamic Dispatch](static-and-dynamic-dispatch.md) + * [Operators and Overloading](operators-and-overloading.md) + * [Generics](generics.md) + * [if let](if-let.md) + * [Trait Objects](trait-objects.md) + * [Closures](closures.md) + * [Universal Function Call Syntax](ufcs.md) + * [Crates and Modules](crates-and-modules.md) + * [`static`](static.md) + * [`const`](const.md) + * [Tuple Structs](tuple-structs.md) + * [Attributes](attributes.md) + * [Conditional Compilation](conditional-compilation.md) + * [`type` aliases](type-aliases.md) + * [Casting between types](casting-between-types.md) + * [Associated Types](associated-types.md) + * [Unsized Types](unsized-types.md) * [Macros](macros.md) - * [Concurrency](concurrency.md) - * [Error Handling](error-handling.md) - * [Documentation](documentation.md) -* [Advanced Topics](advanced.md) - * [FFI](ffi.md) - * [Unsafe Code](unsafe.md) - * [Advanced Macros](advanced-macros.md) -* [Unstable Rust](unstable.md) - * [Compiler Plugins](plugins.md) + * [`unsafe` Code](unsafe-code.md) +* [Nightly Rust](nightly-rust.md) + * [Compiler Plugins](compiler-plugins.md) * [Inline Assembly](inline-assembly.md) * [No stdlib](no-stdlib.md) * [Intrinsics](intrinsics.md) @@ -44,5 +64,6 @@ * [Link args](link-args.md) * [Benchmark Tests](benchmark-tests.md) * [Box Syntax and Patterns](box-syntax-and-patterns.md) -* [Conclusion](conclusion.md) + * [Slice Patterns](slice-patterns.md) * [Glossary](glossary.md) +* [Academic Research](academic-research.md) diff --git a/src/doc/trpl/academic-research.md b/src/doc/trpl/academic-research.md new file mode 100644 index 0000000000..f4f066fb3d --- /dev/null +++ b/src/doc/trpl/academic-research.md @@ -0,0 +1,46 @@ +% Academic Research + +An incomplete list of papers that have had some influence in Rust. + +Recommended for inspiration and a better understanding of Rust's background. + +### Type system + +* [Region based memory management in Cyclone](http://209.68.42.137/ucsd-pages/Courses/cse227.w03/handouts/cyclone-regions.pdf) +* [Safe manual memory management in Cyclone](http://www.cs.umd.edu/projects/PL/cyclone/scp.pdf) +* [Typeclasses: making ad-hoc polymorphism less ad hoc](http://www.ps.uni-sb.de/courses/typen-ws99/class.ps.gz) +* [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) +* [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) + +### Concurrency + +* [Singularity: rethinking the software stack](https://research.microsoft.com/pubs/69431/osr2007_rethinkingsoftwarestack.pdf) +* [Language support for fast and reliable message passing in singularity OS](https://research.microsoft.com/pubs/67482/singsharp.pdf) +* [Scheduling multithreaded computations by work stealing](http://supertech.csail.mit.edu/papers/steal.pdf) +* [Thread scheduling for multiprogramming multiprocessors](http://www.eecis.udel.edu/%7Ecavazos/cisc879-spring2008/papers/arora98thread.pdf) +* [The data locality of work stealing](http://www.aladdin.cs.cmu.edu/papers/pdfs/y2000/locality_spaa00.pdf) +* [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) +* [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) +* [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) + +### Others + +* [Crash-only software](https://www.usenix.org/legacy/events/hotos03/tech/full_papers/candea/candea.pdf) +* [Composing High-Performance Memory Allocators](http://people.cs.umass.edu/~emery/pubs/berger-pldi2001.pdf) +* [Reconsidering Custom Memory Allocation](http://people.cs.umass.edu/~emery/pubs/berger-oopsla2002.pdf) + +### 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 diff --git a/src/doc/trpl/advanced-macros.md b/src/doc/trpl/advanced-macros.md deleted file mode 100644 index fef458caaa..0000000000 --- a/src/doc/trpl/advanced-macros.md +++ /dev/null @@ -1,242 +0,0 @@ -% Advanced macros - -This chapter picks up where the [introductory macro chapter](macros.html) left -off. - -# Syntactic requirements - -Even when Rust code contains un-expanded macros, it can be parsed as a full -[syntax tree][ast]. This property can be very useful for editors and other -tools that process code. It also has a few consequences for the design of -Rust's macro system. - -[ast]: glossary.html#abstract-syntax-tree - -One consequence is that Rust must determine, when it parses a macro invocation, -whether the macro stands in for - -* zero or more items, -* zero or more methods, -* an expression, -* a statement, or -* a pattern. - -A macro invocation within a block could stand for some items, or for an -expression / statement. Rust uses a simple rule to resolve this ambiguity. A -macro invocation that stands for items must be either - -* delimited by curly braces, e.g. `foo! { ... }`, or -* terminated by a semicolon, e.g. `foo!(...);` - -Another consequence of pre-expansion parsing is that the macro invocation must -consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces -must be balanced within a macro invocation. For example, `foo!([)` is -forbidden. This allows Rust to know where the macro invocation ends. - -More formally, the macro invocation body must be a sequence of *token trees*. -A token tree is defined recursively as either - -* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or -* any other single token. - -Within a matcher, each metavariable has a *fragment specifier*, identifying -which syntactic form it matches. - -* `ident`: an identifier. Examples: `x`; `foo`. -* `path`: a qualified name. Example: `T::SpecialA`. -* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. -* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. -* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. -* `stmt`: a single statement. Example: `let x = 3`. -* `block`: a brace-delimited sequence of statements. Example: - `{ log(error, "hi"); return 12; }`. -* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`. -* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`. -* `tt`: a single token tree. - -There are additional rules regarding the next token after a metavariable: - -* `expr` variables must be followed by one of: `=> , ;` -* `ty` and `path` variables must be followed by one of: `=> , : = > as` -* `pat` variables must be followed by one of: `=> , =` -* Other variables may be followed by any token. - -These rules provide some flexibility for Rust's syntax to evolve without -breaking existing macros. - -The macro system does not deal with parse ambiguity at all. For example, the -grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would -be forced to choose between parsing `$t` and parsing `$e`. Changing the -invocation syntax to put a distinctive token in front can solve the problem. In -this case, you can write `$(T $t:ty)* E $e:exp`. - -[item]: ../reference.html#items - -# Scoping and macro import/export - -Macros are expanded at an early stage in compilation, before name resolution. -One downside is that scoping works differently for macros, compared to other -constructs in the language. - -Definition and expansion of macros both happen in a single depth-first, -lexical-order traversal of a crate's source. So a macro defined at module scope -is visible to any subsequent code in the same module, which includes the body -of any subsequent child `mod` items. - -A macro defined within the body of a single `fn`, or anywhere else not at -module scope, is visible only within that item. - -If a module has the `macro_use` attribute, its macros are also visible in its -parent module after the child's `mod` item. If the parent also has `macro_use` -then the macros will be visible in the grandparent after the parent's `mod` -item, and so forth. - -The `macro_use` attribute can also appear on `extern crate`. In this context -it controls which macros are loaded from the external crate, e.g. - -```rust,ignore -#[macro_use(foo, bar)] -extern crate baz; -``` - -If the attribute is given simply as `#[macro_use]`, all macros are loaded. If -there is no `#[macro_use]` attribute then no macros are loaded. Only macros -defined with the `#[macro_export]` attribute may be loaded. - -To load a crate's macros *without* linking it into the output, use `#[no_link]` -as well. - -An example: - -```rust -macro_rules! m1 { () => (()) } - -// visible here: m1 - -mod foo { - // visible here: m1 - - #[macro_export] - macro_rules! m2 { () => (()) } - - // visible here: m1, m2 -} - -// visible here: m1 - -macro_rules! m3 { () => (()) } - -// visible here: m1, m3 - -#[macro_use] -mod bar { - // visible here: m1, m3 - - macro_rules! m4 { () => (()) } - - // visible here: m1, m3, m4 -} - -// visible here: m1, m3, m4 -# fn main() { } -``` - -When this library is loaded with `#[macro_use] extern crate`, only `m2` will -be imported. - -The Rust Reference has a [listing of macro-related -attributes](../reference.html#macro--and-plugin-related-attributes). - -# The variable `$crate` - -A further difficulty occurs when a macro is used in multiple crates. Say that -`mylib` defines - -```rust -pub fn increment(x: u32) -> u32 { - x + 1 -} - -#[macro_export] -macro_rules! inc_a { - ($x:expr) => ( ::increment($x) ) -} - -#[macro_export] -macro_rules! inc_b { - ($x:expr) => ( ::mylib::increment($x) ) -} -# fn main() { } -``` - -`inc_a` only works within `mylib`, while `inc_b` only works outside the -library. Furthermore, `inc_b` will break if the user imports `mylib` under -another name. - -Rust does not (yet) have a hygiene system for crate references, but it does -provide a simple workaround for this problem. Within a macro imported from a -crate named `foo`, the special macro variable `$crate` will expand to `::foo`. -By contrast, when a macro is defined and then used in the same crate, `$crate` -will expand to nothing. This means we can write - -```rust -#[macro_export] -macro_rules! inc { - ($x:expr) => ( $crate::increment($x) ) -} -# fn main() { } -``` - -to define a single macro that works both inside and outside our library. The -function name will expand to either `::increment` or `::mylib::increment`. - -To keep this system simple and correct, `#[macro_use] extern crate ...` may -only appear at the root of your crate, not inside `mod`. This ensures that -`$crate` is a single identifier. - -# The deep end - -The introductory chapter mentioned recursive macros, but it did not give the -full story. Recursive macros are useful for another reason: Each recursive -invocation gives you another opportunity to pattern-match the macro's -arguments. - -As an extreme example, it is possible, though hardly advisable, to implement -the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton -within Rust's macro system. - -```rust -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} -``` - -Exercise: use macros to reduce duplication in the above definition of the -`bct!` macro. - -# Procedural macros - -If Rust's macro system can't do what you need, you may want to write a -[compiler plugin](plugins.html) instead. Compared to `macro_rules!` -macros, this is significantly more work, the interfaces are much less stable, -and bugs can be much harder to track down. In exchange you get the -flexibility of running arbitrary Rust code within the compiler. Syntax -extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/advanced.md b/src/doc/trpl/advanced.md deleted file mode 100644 index 447a8a614b..0000000000 --- a/src/doc/trpl/advanced.md +++ /dev/null @@ -1,8 +0,0 @@ -% Advanced - -In a similar fashion to "Intermediate," this section is full of individual, -deep-dive chapters, which stand alone and can be read in any order. These -chapters focus on the most complex features, as well as some things that -are only available in upcoming versions of Rust. - -After reading "Advanced," you'll be a Rust expert! diff --git a/src/doc/trpl/arrays-vectors-and-slices.md b/src/doc/trpl/arrays-vectors-and-slices.md deleted file mode 100644 index 2916dca2c0..0000000000 --- a/src/doc/trpl/arrays-vectors-and-slices.md +++ /dev/null @@ -1,102 +0,0 @@ -% Arrays, Vectors, and Slices - -Like many programming languages, Rust has list types to represent a sequence of -things. The most basic is the *array*, a fixed-size list of elements of the -same type. By default, arrays are immutable. - -```{rust} -let a = [1, 2, 3]; // a: [i32; 3] -let mut m = [1, 2, 3]; // mut m: [i32; 3] -``` - -There's a shorthand for initializing each element of an array to the same -value. In this example, each element of `a` will be initialized to `0`: - -```{rust} -let a = [0; 20]; // a: [i32; 20] -``` - -Arrays have type `[T; N]`. We'll talk about this `T` notation later, when we -cover generics. - -You can get the number of elements in an array `a` with `a.len()`, and use -`a.iter()` to iterate over them with a for loop. This code will print each -number in order: - -```{rust} -let a = [1, 2, 3]; - -println!("a has {} elements", a.len()); -for e in a.iter() { - println!("{}", e); -} -``` - -You can access a particular element of an array with *subscript notation*: - -```{rust} -let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3] - -println!("The second name is: {}", names[1]); -``` - -Subscripts start at zero, like in most programming languages, so the first name -is `names[0]` and the second name is `names[1]`. The above example prints -`The second name is: Brian`. If you try to use a subscript that is not in the -array, you will get an error: array access is bounds-checked at run-time. Such -errant access is the source of many bugs in other systems programming -languages. - -A *vector* is a dynamic or "growable" array, implemented as the standard -library type [`Vec`](../std/vec/) (we'll talk about what the `` means -later). Vectors always allocate their data on the heap. Vectors are to slices -what `String` is to `&str`. You can create them with the `vec!` macro: - -```{rust} -let v = vec![1, 2, 3]; // v: Vec -``` - -(Notice that unlike the `println!` macro we've used in the past, we use square -brackets `[]` with `vec!`. Rust allows you to use either in either situation, -this is just convention.) - -There's an alternate form of `vec!` for repeating an initial value: - -``` -let v = vec![0; 10]; // ten zeroes -``` - -You can get the length of, iterate over, and subscript vectors just like -arrays. In addition, (mutable) vectors can grow automatically: - -```{rust} -let mut nums = vec![1, 2, 3]; // mut nums: Vec - -nums.push(4); - -println!("The length of nums is now {}", nums.len()); // Prints 4 -``` - -Vectors have many more useful methods. - -A *slice* is a reference to (or "view" into) an array. They are useful for -allowing safe, efficient access to a portion of an array without copying. For -example, you might want to reference just one line of a file read into memory. -By nature, a slice is not created directly, but from an existing variable. -Slices have a length, can be mutable or not, and in many ways behave like -arrays: - -```{rust} -let a = [0, 1, 2, 3, 4]; -let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 - -for e in middle.iter() { - println!("{}", e); // Prints 1, 2, 3 -} -``` - -You can also take a slice of a vector, `String`, or `&str`, because they are -backed by arrays. Slices have type `&[T]`, which we'll talk about when we cover -generics. - -We have now learned all of the most basic Rust concepts. diff --git a/src/doc/trpl/associated-types.md b/src/doc/trpl/associated-types.md index 7161cd33f8..d59239016d 100644 --- a/src/doc/trpl/associated-types.md +++ b/src/doc/trpl/associated-types.md @@ -198,5 +198,5 @@ let obj = Box::new(graph) as Box>; ``` The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N` -type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we +type parameter. Same with `E=Edge`. If we didn’t provide this constraint, we couldn’t be sure which `impl` to match this trait object to. diff --git a/src/doc/trpl/attributes.md b/src/doc/trpl/attributes.md new file mode 100644 index 0000000000..e699bd85f6 --- /dev/null +++ b/src/doc/trpl/attributes.md @@ -0,0 +1,3 @@ +% Attributes + +Coming Soon! diff --git a/src/doc/trpl/basic.md b/src/doc/trpl/basic.md deleted file mode 100644 index c267830e6e..0000000000 --- a/src/doc/trpl/basic.md +++ /dev/null @@ -1,7 +0,0 @@ -% Basics - -This section is a linear introduction to the basic syntax and semantics of -Rust. It has individual sections on each part of Rust's syntax. - -After reading "Basics," you will have a good foundation to learn more about -Rust, and can write very simple programs. diff --git a/src/doc/trpl/benchmark-tests.md b/src/doc/trpl/benchmark-tests.md index 8879653759..890a2f8ae7 100644 --- a/src/doc/trpl/benchmark-tests.md +++ b/src/doc/trpl/benchmark-tests.md @@ -13,7 +13,7 @@ pub fn add_two(a: i32) -> i32 { } #[cfg(test)] -mod tests { +mod test { use super::*; use test::Bencher; diff --git a/src/doc/trpl/casting-between-types.md b/src/doc/trpl/casting-between-types.md new file mode 100644 index 0000000000..8bb0ec6db0 --- /dev/null +++ b/src/doc/trpl/casting-between-types.md @@ -0,0 +1,3 @@ +% Casting Between Types + +Coming Soon diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 01b8163ffd..e3de8eb30b 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -54,7 +54,7 @@ The second is that the syntax is similar, but a bit different. I've added spaces here to make them look a little closer: ```rust -fn plus_one_v1 ( x: i32 ) -> i32 { x + 1 } +fn plus_one_v1 (x: i32 ) -> i32 { x + 1 } let plus_one_v2 = |x: i32 | -> i32 { x + 1 }; let plus_one_v3 = |x: i32 | x + 1 ; ``` @@ -175,9 +175,6 @@ we called `add_num`, it mutated the underlying value, as we'd expect. We also needed to declare `add_num` as `mut` too, because we’re mutating its environment. -We also had to declare `add_num` as mut, since we will be modifying its -environment. - If we change to a `move` closure, it's different: ```rust @@ -208,11 +205,11 @@ you tons of control over what your code does, and closures are no different. Rust's implementation of closures is a bit different than other languages. They are effectively syntax sugar for traits. You'll want to make sure to have read -the [traits chapter][traits] before this one, as well as the chapter on [static -and dynamic dispatch][dispatch], which talks about trait objects. +the [traits chapter][traits] before this one, as well as the chapter on [trait +objects][trait-objects]. [traits]: traits.html -[dispatch]: static-and-dynamic-dispatch.html +[trait-objects]: trait-objects.html Got all that? Good. diff --git a/src/doc/trpl/comments.md b/src/doc/trpl/comments.md index 441496e6a7..fa27d1c226 100644 --- a/src/doc/trpl/comments.md +++ b/src/doc/trpl/comments.md @@ -1,47 +1,45 @@ % Comments -Now that we have some functions, it's a good idea to learn about comments. +Now that we have some functions, it’s a good idea to learn about comments. Comments are notes that you leave to other programmers to help explain things about your code. The compiler mostly ignores them. Rust has two kinds of comments that you should care about: *line comments* and *doc comments*. -```{rust} -// Line comments are anything after '//' and extend to the end of the line. +```rust +// Line comments are anything after ‘//’ and extend to the end of the line. let x = 5; // this is also a line comment. // If you have a long explanation for something, you can put line comments next -// to each other. Put a space between the // and your comment so that it's +// to each other. Put a space between the // and your comment so that it’s // more readable. ``` The other kind of comment is a doc comment. Doc comments use `///` instead of `//`, and support Markdown notation inside: -```{rust} -/// `hello` is a function that prints a greeting that is personalized based on -/// the name given. -/// -/// # Arguments -/// -/// * `name` - The name of the person you'd like to greet. +```rust +/// Adds one to the number given. /// /// # Examples /// -/// ```rust -/// let name = "Steve"; -/// hello(name); // prints "Hello, Steve!" /// ``` -fn hello(name: &str) { - println!("Hello, {}!", name); +/// let five = 5; +/// +/// assert_eq!(6, add_one(5)); +/// ``` +fn add_one(x: i32) -> i32 { + x + 1 } ``` -When writing doc comments, adding sections for any arguments, return values, -and providing some examples of usage is very, very helpful. Don't worry about -the `&str`, we'll get to it soon. +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 +in documentation. There’s another macro, `assert!`, which `panic!`s if the +value passed to it is `false`. You can use the [`rustdoc`](documentation.html) tool to generate HTML documentation -from these doc comments. +from these doc comments, and also to run the code examples as tests! diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/compiler-plugins.md similarity index 100% rename from src/doc/trpl/plugins.md rename to src/doc/trpl/compiler-plugins.md diff --git a/src/doc/trpl/compound-data-types.md b/src/doc/trpl/compound-data-types.md deleted file mode 100644 index e44d2edd66..0000000000 --- a/src/doc/trpl/compound-data-types.md +++ /dev/null @@ -1,364 +0,0 @@ -% Compound Data Types - -Rust, like many programming languages, has a number of different data types -that are built-in. You've already done some simple work with integers and -strings, but next, let's talk about some more complicated ways of storing data. - -## Tuples - -The first compound data type we're going to talk about is called the *tuple*. -A tuple is an ordered list of fixed size. Like this: - -```rust -let x = (1, "hello"); -``` - -The parentheses and commas form this two-length tuple. Here's the same code, but -with the type annotated: - -```rust -let x: (i32, &str) = (1, "hello"); -``` - -As you can see, the type of a tuple looks just like the tuple, but with each -position having a type name rather than the value. Careful readers will also -note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. -You have briefly seen `&str` used as a type before, and we'll discuss the -details of strings later. In systems programming languages, strings are a bit -more complex than in other languages. For now, just read `&str` as a *string -slice*, and we'll learn more soon. - -You can access the fields in a tuple through a *destructuring let*. Here's -an example: - -```rust -let (x, y, z) = (1, 2, 3); - -println!("x is {}", x); -``` - -Remember before when I said the left-hand side of a `let` statement was more -powerful than just assigning a binding? Here we are. We can put a pattern on -the left-hand side of the `let`, and if it matches up to the right-hand side, -we can assign multiple bindings at once. In this case, `let` "destructures," -or "breaks up," the tuple, and assigns the bits to three bindings. - -This pattern is very powerful, and we'll see it repeated more later. - -There are also a few things you can do with a tuple as a whole, without -destructuring. You can assign one tuple into another, if they have the same -contained types and [arity]. Tuples have the same arity when they have the same -length. - -```rust -let mut x = (1, 2); // x: (i32, i32) -let y = (2, 3); // y: (i32, i32) - -x = y; -``` - -You can also check for equality with `==`. Again, this will only compile if the -tuples have the same type. - -```rust -let x = (1, 2, 3); -let y = (2, 2, 4); - -if x == y { - println!("yes"); -} else { - println!("no"); -} -``` - -This will print `no`, because some of the values aren't equal. - -Note that the order of the values is considered when checking for equality, -so the following example will also print `no`. - -```rust -let x = (1, 2, 3); -let y = (2, 1, 3); - -if x == y { - println!("yes"); -} else { - println!("no"); -} -``` - -One other use of tuples is to return multiple values from a function: - -```rust -fn next_two(x: i32) -> (i32, i32) { (x + 1, x + 2) } - -fn main() { - let (x, y) = next_two(5); - println!("x, y = {}, {}", x, y); -} -``` - -Even though Rust functions can only return one value, a tuple *is* one value, -that happens to be made up of more than one value. You can also see in this -example how you can destructure a pattern returned by a function, as well. - -Tuples are a very simple data structure, and so are not often what you want. -Let's move on to their bigger sibling, structs. - -## Structs - -A struct is another form of a *record type*, just like a tuple. There's a -difference: structs give each element that they contain a name, called a -*field* or a *member*. Check it out: - -```rust -struct Point { - x: i32, - y: i32, -} - -fn main() { - let origin = Point { x: 0, y: 0 }; // origin: Point - - println!("The origin is at ({}, {})", origin.x, origin.y); -} -``` - -There's a lot going on here, so let's break it down. We declare a struct with -the `struct` keyword, and then with a name. By convention, structs begin with a -capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`. - -We can create an instance of our struct via `let`, as usual, but we use a `key: -value` style syntax to set each field. The order doesn't need to be the same as -in the original declaration. - -Finally, because fields have names, we can access the field through dot -notation: `origin.x`. - -The values in structs are immutable by default, like other bindings in Rust. -Use `mut` to make them mutable: - -```{rust} -struct Point { - x: i32, - y: i32, -} - -fn main() { - let mut point = Point { x: 0, y: 0 }; - - point.x = 5; - - println!("The point is at ({}, {})", point.x, point.y); -} -``` - -This will print `The point is at (5, 0)`. - -## Tuple Structs and Newtypes - -Rust has another data type that's like a hybrid between a tuple and a struct, -called a *tuple struct*. Tuple structs do have a name, but their fields don't: - - -```{rust} -struct Color(i32, i32, i32); -struct Point(i32, i32, i32); -``` - -These two will not be equal, even if they have the same values: - -```{rust} -# struct Color(i32, i32, i32); -# struct Point(i32, i32, i32); -let black = Color(0, 0, 0); -let origin = Point(0, 0, 0); -``` - -It is almost always better to use a struct than a tuple struct. We would write -`Color` and `Point` like this instead: - -```{rust} -struct Color { - red: i32, - blue: i32, - green: i32, -} - -struct Point { - x: i32, - y: i32, - z: i32, -} -``` - -Now, we have actual names, rather than positions. Good names are important, -and with a struct, we have actual names. - -There _is_ one case when a tuple struct is very useful, though, and that's a -tuple struct with only one element. We call this the *newtype* pattern, because -it allows you to create a new type, distinct from that of its contained value -and expressing its own semantic meaning: - -```{rust} -struct Inches(i32); - -let length = Inches(10); - -let Inches(integer_length) = length; -println!("length is {} inches", integer_length); -``` - -As you can see here, you can extract the inner integer type through a -destructuring `let`, as we discussed previously in 'tuples.' In this case, the -`let Inches(integer_length)` assigns `10` to `integer_length`. - -## Enums - -Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful -feature of Rust, and are used throughout the standard library. An `enum` is -a type which relates a set of alternates to a specific name. For example, below -we define `Character` to be either a `Digit` or something else. These -can be used via their fully scoped names: `Character::Other` (more about `::` -below). - -```rust -enum Character { - Digit(i32), - Other, -} -``` - -Most normal types are allowed as the variant components of an `enum`. Here are -some examples: - -```rust -struct Empty; -struct Color(i32, i32, i32); -struct Length(i32); -struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 } -struct HeightDatabase(Vec); -``` - -You see that, depending on its type, an `enum` variant may or may not hold data. -In `Character`, for instance, `Digit` gives a meaningful name for an `i32` -value, where `Other` is only a name. However, the fact that they represent -distinct categories of `Character` is a very useful property. - -As with structures, the variants of an enum by default are not comparable with -equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not -support other binary operations such as `*` and `+`. As such, the following code -is invalid for the example `Character` type: - -```{rust,ignore} -// These assignments both succeed -let ten = Character::Digit(10); -let four = Character::Digit(4); - -// Error: `*` is not implemented for type `Character` -let forty = ten * four; - -// Error: `<=` is not implemented for type `Character` -let four_is_smaller = four <= ten; - -// Error: `==` is not implemented for type `Character` -let four_equals_ten = four == ten; -``` - -This may seem rather limiting, but it's a limitation which we can overcome. -There are two ways: by implementing equality ourselves, or by pattern matching -variants with [`match`][match] expressions, which you'll learn in the next -chapter. We don't know enough about Rust to implement equality yet, but we can -use the `Ordering` enum from the standard library, which does: - -``` -enum Ordering { - Less, - Equal, - Greater, -} -``` - -Because `Ordering` has already been defined for us, we will import it with the -`use` keyword. Here's an example of how it is used: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); // ordering: Ordering - - if ordering == Ordering::Less { - println!("less"); - } else if ordering == Ordering::Greater { - println!("greater"); - } else if ordering == Ordering::Equal { - println!("equal"); - } -} -``` - -The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives -in the `cmp` submodule of the `std` module. We'll talk more about modules later -in the guide. For now, all you need to know is that you can `use` things from -the standard library if you need them. - -Okay, let's talk about the actual code in the example. `cmp` is a function that -compares two things, and returns an `Ordering`. We return either -`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on -whether the first value is less than, greater than, or equal to the second. Note -that each variant of the `enum` is namespaced under the `enum` itself: it's -`Ordering::Greater`, not `Greater`. - -The `ordering` variable has the type `Ordering`, and so contains one of the -three values. We then do a bunch of `if`/`else` comparisons to check which -one it is. - -This `Ordering::Greater` notation is too long. Let's use another form of `use` -to import the `enum` variants instead. This will avoid full scoping: - -```{rust} -use std::cmp::Ordering::{self, Equal, Less, Greater}; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Less } - else if a > b { Greater } - else { Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); // ordering: Ordering - - if ordering == Less { println!("less"); } - else if ordering == Greater { println!("greater"); } - else if ordering == Equal { println!("equal"); } -} -``` - -Importing variants is convenient and compact, but can also cause name conflicts, -so do this with caution. For this reason, it's normally considered better style -to `use` an enum rather than its variants directly. - -As you can see, `enum`s are quite a powerful tool for data representation, and -are even more useful when they're [generic][generics] across types. Before we -get to generics, though, let's talk about how to use enums with pattern -matching, a tool that will let us deconstruct sum types (the type theory term -for enums) like `Ordering` in a very elegant way that avoids all these messy -and brittle `if`/`else`s. - - -[arity]: ./glossary.html#arity -[match]: ./match.html -[generics]: ./generics.html diff --git a/src/doc/trpl/conclusion.md b/src/doc/trpl/conclusion.md deleted file mode 100644 index 9afddb1131..0000000000 --- a/src/doc/trpl/conclusion.md +++ /dev/null @@ -1,11 +0,0 @@ -% Conclusion - -We covered a lot of ground here. When you've mastered everything in this Guide, -you will have a firm grasp of Rust development. There's a whole lot more -out there, though, we've just covered the surface. There's tons of topics that -you can dig deeper into, e.g. by reading the API documentation of the -[standard library](http://doc.rust-lang.org/std/), by discovering solutions for -common problems on [Rust by Example](http://rustbyexample.com/), or by browsing -crates written by the community on [crates.io](https://crates.io/). - -Happy hacking! diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index 6b814a6854..159e04e942 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -56,71 +56,35 @@ place! ## Threads -Rust's standard library provides a library for 'threads', which allow you to +Rust's standard library provides a library for threads, which allow you to run Rust code in parallel. Here's a basic example of using `std::thread`: ``` use std::thread; fn main() { - thread::scoped(|| { + thread::spawn(|| { println!("Hello from a thread!"); }); } ``` -The `thread::scoped()` method accepts a closure, which is executed in a new -thread. It's called `scoped` because this thread returns a join guard: +The `thread::spawn()` method accepts a closure, which is executed in a +new thread. It returns a handle to the thread, that can be used to +wait for the child thread to finish and extract its result: ``` use std::thread; fn main() { - let guard = thread::scoped(|| { - println!("Hello from a thread!"); + let handle = thread::spawn(|| { + "Hello from a thread!" }); - // guard goes out of scope here + println!("{}", handle.join().unwrap()); } ``` -When `guard` goes out of scope, it will block execution until the thread is -finished. If we didn't want this behaviour, we could use `thread::spawn()`: - -``` -# #![feature(old_io, std_misc)] -use std::thread; -use std::old_io::timer; -use std::time::Duration; - -fn main() { - thread::spawn(|| { - println!("Hello from a thread!"); - }); - - timer::sleep(Duration::milliseconds(50)); -} -``` - -We need to `sleep` here because when `main()` ends, it kills all of the -running threads. - -[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting -type signature: - -```text -fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> - where T: Send + 'a, - F: FnOnce() -> T, - F: Send + 'a -``` - -Specifically, `F`, the closure that we pass to execute in the new thread. It -has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce` -allows the closure to take ownership of any data it mentions from the parent -thread. The other restriction is that `F` must be `Send`. We aren't allowed to -transfer this ownership unless the type thinks that's okay. - Many languages have the ability to execute threads, but it's wildly unsafe. There are entire books about how to prevent errors that occur from shared mutable state. Rust helps out with its type system here as well, by preventing @@ -147,10 +111,7 @@ As an example, here is a Rust program that would have a data race in many languages. It will not compile: ```ignore -# #![feature(old_io, std_misc)] use std::thread; -use std::old_io::timer; -use std::time::Duration; fn main() { let mut data = vec![1u32, 2, 3]; @@ -161,14 +122,14 @@ fn main() { }); } - timer::sleep(Duration::milliseconds(50)); + thread::sleep_ms(50); } ``` This gives us an error: ```text -12:17 error: capture of moved value: `data` +8:17 error: capture of moved value: `data` data[i] += 1; ^~~~ ``` @@ -187,10 +148,7 @@ only one person at a time can mutate what's inside. For that, we can use the but for a different reason: ```ignore -# #![feature(old_io, std_misc)] use std::thread; -use std::old_io::timer; -use std::time::Duration; use std::sync::Mutex; fn main() { @@ -203,17 +161,17 @@ fn main() { }); } - timer::sleep(Duration::milliseconds(50)); + thread::sleep_ms(50); } ``` Here's the error: ```text -:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] +:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] :11 thread::spawn(move || { ^~~~~~~~~~~~~ -:11:9: 11:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely +:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely :11 thread::spawn(move || { ^~~~~~~~~~~~~ ``` @@ -232,11 +190,8 @@ guard across thread boundaries, which gives us our error. We can use `Arc` to fix this. Here's the working version: ``` -# #![feature(old_io, std_misc)] use std::sync::{Arc, Mutex}; use std::thread; -use std::old_io::timer; -use std::time::Duration; fn main() { let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); @@ -249,7 +204,7 @@ fn main() { }); } - timer::sleep(Duration::milliseconds(50)); + thread::sleep_ms(50); } ``` @@ -257,12 +212,9 @@ We now call `clone()` on our `Arc`, which increases the internal count. This handle is then moved into the new thread. Let's examine the body of the thread more closely: -``` -# #![feature(old_io, std_misc)] +```rust # use std::sync::{Arc, Mutex}; # use std::thread; -# use std::old_io::timer; -# use std::time::Duration; # fn main() { # let data = Arc::new(Mutex::new(vec![1u32, 2, 3])); # for i in 0..2 { @@ -272,6 +224,7 @@ thread::spawn(move || { data[i] += 1; }); # } +# thread::sleep_ms(50); # } ``` diff --git a/src/doc/trpl/conditional-compilation.md b/src/doc/trpl/conditional-compilation.md new file mode 100644 index 0000000000..40367fa844 --- /dev/null +++ b/src/doc/trpl/conditional-compilation.md @@ -0,0 +1,3 @@ +% Conditional Compilation + +Coming Soon! diff --git a/src/doc/trpl/const.md b/src/doc/trpl/const.md new file mode 100644 index 0000000000..9234c4fc2f --- /dev/null +++ b/src/doc/trpl/const.md @@ -0,0 +1,3 @@ +% `const` + +Coming soon! diff --git a/src/doc/trpl/crates-and-modules.md b/src/doc/trpl/crates-and-modules.md index 0cc54c9b16..83e8cc629f 100644 --- a/src/doc/trpl/crates-and-modules.md +++ b/src/doc/trpl/crates-and-modules.md @@ -111,8 +111,8 @@ Cargo will build this crate as a library: ```bash $ cargo build Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -$ ls target -deps libphrases-a7448e02a0468eaa.rlib native +$ ls target/debug +build deps examples libphrases-a7448e02a0468eaa.rlib native ``` `libphrase-hash.rlib` is the compiled crate. Before we see how to use this @@ -163,9 +163,12 @@ $ tree . │   │   └── mod.rs │   └── lib.rs └── target - ├── deps - ├── libphrases-a7448e02a0468eaa.rlib - └── native + └── debug + ├── build + ├── deps + ├── examples + ├── libphrases-a7448e02a0468eaa.rlib + └── native ``` `src/lib.rs` is our crate root, and looks like this: @@ -214,8 +217,6 @@ fn goodbye() -> String { Put this in `src/japanese/greetings.rs`: ```rust -// in src/japanese/greetings.rs - fn hello() -> String { "こんにちは".to_string() } @@ -275,14 +276,15 @@ this: ```bash $ cargo build Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -/home/you/projects/phrases/src/main.rs:4:38: 4:72 error: function `hello` is private -/home/you/projects/phrases/src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello()); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +src/main.rs:4:38: 4:72 error: function `hello` is private +src/main.rs:4 println!("Hello in English: {}", phrases::english::greetings::hello()); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ note: in expansion of format_args! -:2:23: 2:77 note: expansion site -:1:1: 3:2 note: in expansion of println! -/home/you/projects/phrases/src/main.rs:4:5: 4:76 note: expansion site - +:2:25: 2:58 note: expansion site +:1:1: 2:62 note: in expansion of print! +:3:1: 3:54 note: expansion site +:1:1: 3:58 note: in expansion of println! +phrases/src/main.rs:4:5: 4:76 note: expansion site ``` By default, everything is private in Rust. Let's talk about this in some more @@ -340,15 +342,15 @@ functions: ```bash $ cargo run Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -/home/you/projects/phrases/src/japanese/greetings.rs:1:1: 3:2 warning: code is never used: `hello`, #[warn(dead_code)] on by default -/home/you/projects/phrases/src/japanese/greetings.rs:1 fn hello() -> String { -/home/you/projects/phrases/src/japanese/greetings.rs:2 "こんにちは".to_string() -/home/you/projects/phrases/src/japanese/greetings.rs:3 } -/home/you/projects/phrases/src/japanese/farewells.rs:1:1: 3:2 warning: code is never used: `goodbye`, #[warn(dead_code)] on by default -/home/you/projects/phrases/src/japanese/farewells.rs:1 fn goodbye() -> String { -/home/you/projects/phrases/src/japanese/farewells.rs:2 "さようなら".to_string() -/home/you/projects/phrases/src/japanese/farewells.rs:3 } - Running `target/phrases` +src/japanese/greetings.rs:1:1: 3:2 warning: function is never used: `hello`, #[warn(dead_code)] on by default +src/japanese/greetings.rs:1 fn hello() -> String { +src/japanese/greetings.rs:2 "こんにちは".to_string() +src/japanese/greetings.rs:3 } +src/japanese/farewells.rs:1:1: 3:2 warning: function is never used: `goodbye`, #[warn(dead_code)] on by default +src/japanese/farewells.rs:1 fn goodbye() -> String { +src/japanese/farewells.rs:2 "さようなら".to_string() +src/japanese/farewells.rs:3 } + Running `target/debug/phrases` Hello in English: Hello! Goodbye in English: Goodbye. ``` @@ -414,9 +416,9 @@ Rust will give us a compile-time error: ```text Compiling phrases v0.0.1 (file:///home/you/projects/phrases) -/home/you/projects/phrases/src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module -/home/you/projects/phrases/src/main.rs:4 use phrases::japanese::greetings::hello; - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +src/main.rs:4:5: 4:40 error: a value named `hello` has already been imported in this module [E0252] +src/main.rs:4 use phrases::japanese::greetings::hello; + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error Could not compile `phrases`. ``` @@ -523,7 +525,7 @@ This will build and run: ```bash $ cargo run Compiling phrases v0.0.1 (file:///home/you/projects/phrases) - Running `target/phrases` + Running `target/debug/phrases` Hello in English: Hello! Goodbye in English: Goodbye. Hello in Japanese: こんにちは diff --git a/src/doc/trpl/debug-and-display.md b/src/doc/trpl/debug-and-display.md new file mode 100644 index 0000000000..918f4c440a --- /dev/null +++ b/src/doc/trpl/debug-and-display.md @@ -0,0 +1,3 @@ +% Debug and Display + +Coming soon! diff --git a/src/doc/trpl/deref-coercions.md b/src/doc/trpl/deref-coercions.md new file mode 100644 index 0000000000..afacd30405 --- /dev/null +++ b/src/doc/trpl/deref-coercions.md @@ -0,0 +1,3 @@ +% `Deref` coercions + +Coming soon! diff --git a/src/doc/trpl/drop.md b/src/doc/trpl/drop.md new file mode 100644 index 0000000000..af58e23561 --- /dev/null +++ b/src/doc/trpl/drop.md @@ -0,0 +1,3 @@ +% `Drop` + +Coming soon! diff --git a/src/doc/trpl/effective-rust.md b/src/doc/trpl/effective-rust.md new file mode 100644 index 0000000000..582ed3b7e6 --- /dev/null +++ b/src/doc/trpl/effective-rust.md @@ -0,0 +1,8 @@ +% Effective Rust + +So you’ve learned how to write some Rust code. But there’s a difference between +writing *any* Rust code and writing *good* Rust code. + +This section consists of relatively independent tutorials which show you how to +take your Rust to the next level. Common patterns and standard library features +will be introduced. Read these sections in any order of your choosing. diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md new file mode 100644 index 0000000000..504bd09917 --- /dev/null +++ b/src/doc/trpl/enums.md @@ -0,0 +1,147 @@ +% Enums + +Finally, Rust has a "sum type", an *enum*. Enums are an incredibly useful +feature of Rust, and are used throughout the standard library. An `enum` is +a type which relates a set of alternates to a specific name. For example, below +we define `Character` to be either a `Digit` or something else. These +can be used via their fully scoped names: `Character::Other` (more about `::` +below). + +```rust +enum Character { + Digit(i32), + Other, +} +``` + +Most normal types are allowed as the variant components of an `enum`. Here are +some examples: + +```rust +struct Empty; +struct Color(i32, i32, i32); +struct Length(i32); +struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 } +struct HeightDatabase(Vec); +``` + +You see that, depending on its type, an `enum` variant may or may not hold data. +In `Character`, for instance, `Digit` gives a meaningful name for an `i32` +value, where `Other` is only a name. However, the fact that they represent +distinct categories of `Character` is a very useful property. + +As with structures, the variants of an enum by default are not comparable with +equality operators (`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not +support other binary operations such as `*` and `+`. As such, the following code +is invalid for the example `Character` type: + +```{rust,ignore} +// These assignments both succeed +let ten = Character::Digit(10); +let four = Character::Digit(4); + +// Error: `*` is not implemented for type `Character` +let forty = ten * four; + +// Error: `<=` is not implemented for type `Character` +let four_is_smaller = four <= ten; + +// Error: `==` is not implemented for type `Character` +let four_equals_ten = four == ten; +``` + +This may seem rather limiting, but it's a limitation which we can overcome. +There are two ways: by implementing equality ourselves, or by pattern matching +variants with [`match`][match] expressions, which you'll learn in the next +chapter. We don't know enough about Rust to implement equality yet, but we can +use the `Ordering` enum from the standard library, which does: + +``` +enum Ordering { + Less, + Equal, + Greater, +} +``` + +Because `Ordering` has already been defined for us, we will import it with the +`use` keyword. Here's an example of how it is used: + +```{rust} +use std::cmp::Ordering; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Ordering::Less } + else if a > b { Ordering::Greater } + else { Ordering::Equal } +} + +fn main() { + let x = 5; + let y = 10; + + let ordering = cmp(x, y); // ordering: Ordering + + if ordering == Ordering::Less { + println!("less"); + } else if ordering == Ordering::Greater { + println!("greater"); + } else if ordering == Ordering::Equal { + println!("equal"); + } +} +``` + +The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives +in the `cmp` submodule of the `std` module. We'll talk more about modules later +in the guide. For now, all you need to know is that you can `use` things from +the standard library if you need them. + +Okay, let's talk about the actual code in the example. `cmp` is a function that +compares two things, and returns an `Ordering`. We return either +`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on +whether the first value is less than, greater than, or equal to the second. Note +that each variant of the `enum` is namespaced under the `enum` itself: it's +`Ordering::Greater`, not `Greater`. + +The `ordering` variable has the type `Ordering`, and so contains one of the +three values. We then do a bunch of `if`/`else` comparisons to check which +one it is. + +This `Ordering::Greater` notation is too long. Let's use another form of `use` +to import the `enum` variants instead. This will avoid full scoping: + +```{rust} +use std::cmp::Ordering::{self, Equal, Less, Greater}; + +fn cmp(a: i32, b: i32) -> Ordering { + if a < b { Less } + else if a > b { Greater } + else { Equal } +} + +fn main() { + let x = 5; + let y = 10; + + let ordering = cmp(x, y); // ordering: Ordering + + if ordering == Less { println!("less"); } + else if ordering == Greater { println!("greater"); } + else if ordering == Equal { println!("equal"); } +} +``` + +Importing variants is convenient and compact, but can also cause name conflicts, +so do this with caution. For this reason, it's normally considered better style +to `use` an enum rather than its variants directly. + +As you can see, `enum`s are quite a powerful tool for data representation, and +are even more useful when they're [generic][generics] across types. Before we +get to generics, though, let's talk about how to use enums with pattern +matching, a tool that will let us deconstruct sum types (the type theory term +for enums) like `Ordering` in a very elegant way that avoids all these messy +and brittle `if`/`else`s. + +[match]: ./match.html +[generics]: ./generics.html diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index b9e7bd78c5..491f7b0c2a 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -297,5 +297,5 @@ It's worth noting that you can only use `try!` from a function that returns a `Result`, which means that you cannot use `try!` inside of `main()`, because `main()` doesn't return anything. -`try!` makes use of [`FromError`](../std/error/#the-fromerror-trait) to determine +`try!` makes use of [`From`](../std/convert/trait.From.hml) to determine what to return in the error case. diff --git a/src/doc/trpl/ffi.md b/src/doc/trpl/ffi.md index 23f6e17b86..2c5e6b2e5f 100644 --- a/src/doc/trpl/ffi.md +++ b/src/doc/trpl/ffi.md @@ -166,7 +166,7 @@ pub fn uncompress(src: &[u8]) -> Option> { } ``` -For reference, the examples used here are also available as an [library on +For reference, the examples used here are also available as a [library on GitHub](https://github.com/thestinger/rust-snappy). # Destructors diff --git a/src/doc/trpl/for-loops.md b/src/doc/trpl/for-loops.md new file mode 100644 index 0000000000..1e3f2fa54b --- /dev/null +++ b/src/doc/trpl/for-loops.md @@ -0,0 +1,43 @@ +% 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. diff --git a/src/doc/trpl/functions.md b/src/doc/trpl/functions.md index 8e8ee8d63d..87af48532a 100644 --- a/src/doc/trpl/functions.md +++ b/src/doc/trpl/functions.md @@ -1,6 +1,6 @@ % Functions -You've already seen one function so far, the `main` function: +Every Rust program has at least one function, the `main` function: ```rust fn main() { @@ -8,16 +8,16 @@ fn main() { ``` This is the simplest possible function declaration. As we mentioned before, -`fn` says "this is a function," followed by the name, some parentheses because +`fn` says ‘this is a function’, followed by the name, some parentheses because this function takes no arguments, and then some curly braces to indicate the -body. Here's a function named `foo`: +body. Here’s a function named `foo`: ```rust fn foo() { } ``` -So, what about taking arguments? Here's a function that prints a number: +So, what about taking arguments? Here’s a function that prints a number: ```rust fn print_number(x: i32) { @@ -25,7 +25,7 @@ fn print_number(x: i32) { } ``` -Here's a complete program that uses `print_number`: +Here’s a complete program that uses `print_number`: ```rust fn main() { @@ -40,7 +40,7 @@ fn print_number(x: i32) { As you can see, function arguments work very similar to `let` declarations: you add a type to the argument name, after a colon. -Here's a complete program that adds two numbers together and prints them: +Here’s a complete program that adds two numbers together and prints them: ```rust fn main() { @@ -58,7 +58,7 @@ as when you declare it. Unlike `let`, you _must_ declare the types of function arguments. This does not work: -```{rust,ignore} +```rust,ignore fn print_sum(x, y) { println!("sum is: {}", x + y); } @@ -67,8 +67,8 @@ fn print_sum(x, y) { You get this error: ```text -hello.rs:5:18: 5:19 expected one of `!`, `:`, or `@`, found `)` -hello.rs:5 fn print_number(x, y) { +expected one of `!`, `:`, or `@`, found `)` +fn print_number(x, y) { ``` This is a deliberate design decision. While full-program inference is possible, @@ -77,7 +77,7 @@ types explicitly is a best-practice. We agree that forcing functions to declare types while allowing for inference inside of function bodies is a wonderful sweet spot between full inference and no inference. -What about returning a value? Here's a function that adds one to an integer: +What about returning a value? Here’s a function that adds one to an integer: ```rust fn add_one(x: i32) -> i32 { @@ -86,11 +86,11 @@ fn add_one(x: i32) -> i32 { ``` Rust functions return exactly one value, and you declare the type after an -"arrow," which is a dash (`-`) followed by a greater-than sign (`>`). +‘arrow’, which is a dash (`-`) followed by a greater-than sign (`>`). The last +line of a function determines what it returns. You’ll note the lack of a +semicolon here. If we added it in: -You'll note the lack of a semicolon here. If we added it in: - -```{rust,ignore} +```rust,ignore fn add_one(x: i32) -> i32 { x + 1; } @@ -109,60 +109,99 @@ help: consider removing this semicolon: ^ ``` -Remember our earlier discussions about semicolons and `()`? Our function claims -to return an `i32`, but with a semicolon, it would return `()` instead. Rust -realizes this probably isn't what we want, and suggests removing the semicolon. +This reveals two interesting things about Rust: it is an expression-based +language, and semicolons are different from semicolons in other ‘curly brace +and semicolon’-based languages. These two things are related. -This is very much like our `if` statement before: the result of the block -(`{}`) is the value of the expression. Other expression-oriented languages, -such as Ruby, work like this, but it's a bit unusual in the systems programming -world. When people first learn about this, they usually assume that it -introduces bugs. But because Rust's type system is so strong, and because unit -is its own unique type, we have never seen an issue where adding or removing a -semicolon in a return position would cause a bug. +## Expressions vs. Statements -But what about early returns? Rust does have a keyword for that, `return`: +Rust is primarily an expression-based language. There are only two kinds of +statements, and everything else is an expression. -```rust -fn foo(x: i32) -> i32 { - if x < 5 { return x; } +So what's the difference? Expressions return a value, and statements do not. +That’s why we end up with ‘not all control paths return a value’ here: the +statement `x + 1;` doesn’t return a value. There are two kinds of statements in +Rust: ‘declaration statements’ and ‘expression statements’. Everything else is +an expression. Let’s talk about declaration statements first. + +In some languages, variable bindings can be written as expressions, not just +statements. Like Ruby: + +```ruby +x = y = 5 +``` + +In Rust, however, using `let` to introduce a binding is _not_ an expression. The +following will produce a compile-time error: + +```ignore +let x = (let y = 5); // expected identifier, found keyword `let` +``` + +The compiler is telling us here that it was expecting to see the beginning of +an expression, and a `let` can only begin a statement, not an expression. + +Note that assigning to an already-bound variable (e.g. `y = 5`) is still an +expression, although its value is not particularly useful. Unlike other +languages where an assignment evaluates to the assigned value (e.g. `5` in the +previous example), in Rust the value of an assignment is an empty tuple `()`: + +``` +let mut y = 5; + +let x = (y = 6); // x has the value `()`, not `6` +``` + +The second kind of statement in Rust is the *expression statement*. Its +purpose is to turn any expression into a statement. In practical terms, Rust's +grammar expects statements to follow other statements. This means that you use +semicolons to separate expressions from each other. This means that Rust +looks a lot like most other languages that require you to use semicolons +at the end of every line, and you will see semicolons at the end of almost +every line of Rust code you see. +What is this exception that makes us say "almost"? You saw it already, in this +code: + +```rust +fn add_one(x: i32) -> i32 { x + 1 } ``` -Using a `return` as the last line of a function works, but is considered poor -style: +Our function claims to return an `i32`, but with a semicolon, it would return +`()` instead. Rust realizes this probably isn’t what we want, and suggests +removing the semicolon in the error we saw before. + +## Early returns + +But what about early returns? Rust does have a keyword for that, `return`: ```rust fn foo(x: i32) -> i32 { - if x < 5 { return x; } + return x; - return x + 1; + // we never run this code! + x + 1 } ``` -The previous definition without `return` may look a bit strange if you haven't -worked in an expression-based language before, but it becomes intuitive over -time. If this were production code, we wouldn't write it in that way anyway, -we'd write this: +Using a `return` as the last line of a function works, but is considered poor +style: ```rust fn foo(x: i32) -> i32 { - if x < 5 { - x - } else { - x + 1 - } + return x + 1; } ``` -Because `if` is an expression, and it's the only expression in this function, -the value will be the result of the `if`. +The previous definition without `return` may look a bit strange if you haven’t +worked in an expression-based language before, but it becomes intuitive over +time. ## Diverging functions -Rust has some special syntax for 'diverging functions', which are functions that +Rust has some special syntax for ‘diverging functions’, which are functions that do not return: ``` @@ -171,23 +210,18 @@ fn diverges() -> ! { } ``` -`panic!` is a macro, similar to `println!()` that we've already seen. Unlike +`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike `println!()`, `panic!()` causes the current thread of execution to crash with the given message. Because this function will cause a crash, it will never return, and so it has -the type '`!`', which is read "diverges." A diverging function can be used +the type ‘`!`’, which is read ‘diverges’. A diverging function can be used as any type: ```should_panic # fn diverges() -> ! { # panic!("This function never returns!"); # } - let x: i32 = diverges(); let x: String = diverges(); ``` - -We don't have a good use for diverging functions yet, because they're used in -conjunction with other Rust features. But when you see `-> !` later, you'll -know what it's called. diff --git a/src/doc/trpl/getting-started.md b/src/doc/trpl/getting-started.md new file mode 100644 index 0000000000..555d40e659 --- /dev/null +++ b/src/doc/trpl/getting-started.md @@ -0,0 +1,5 @@ +% Getting Started + +This first section of the book will get you going with Rust and its tooling. +First, we’ll install Rust. Then: the classic ‘Hello World’ program. Finally, +we’ll talk about Cargo, Rust’s build system and package manager. diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index b45211e3a0..8d8b173433 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -1,26 +1,27 @@ % Hello, Cargo! -[Cargo](http://crates.io) is a tool that Rustaceans use to help manage their -Rust projects. Cargo is currently in an alpha state, just like Rust, and so it -is still a work in progress. However, it is already good enough to use for many -Rust projects, and so it is assumed that Rust projects will use Cargo from the -beginning. +[Cargo][cratesio] is a tool that Rustaceans use to help manage their Rust +projects. Cargo is currently in a pre-1.0 state, and so it is still a work in +progress. However, it is already good enough to use for many Rust projects, and +so it is assumed that Rust projects will use Cargo from the beginning. + +[cratesio]: https://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 +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 -README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) -for specific instructions about installing it. +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 +README][cargoreadme] for specific instructions about installing it. + +[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies ## Converting to Cargo -Let's convert Hello World to Cargo. +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 @@ -52,14 +53,9 @@ Put this inside: name = "hello_world" version = "0.0.1" authors = [ "Your name " ] - -[[bin]] - -name = "hello_world" ``` -This file is in the [TOML](https://github.com/toml-lang/toml) format. Let's let -it explain itself to you: +This file is in the [TOML][toml] format. Let’s let it explain itself to you: > 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. @@ -68,10 +64,7 @@ it explain itself to you: TOML is very similar to INI, but with some extra goodies. -Anyway, there are two *tables* in this file: `package` and `bin`. The first -tells Cargo metadata about your package. The second tells Cargo that we're -interested in building a binary, not a library (though we could do both!), as -well as what it is named. +[toml]: https://github.com/toml-lang/toml Once you have this file in place, we should be ready to build! Try this: @@ -83,13 +76,32 @@ Hello, world! ``` Bam! We build our project with `cargo build`, and run it with -`./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use -of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` more than once and pass it a bunch of options to -tell it to build everything together. With Cargo, as our project grows, we can -just `cargo build`, and it'll work the right way. When your project is finally -ready for release, you can use `cargo build --release` to compile your crates with -optimizations. +`./target/debug/hello_world`. We can do both in one step with `cargo run`: + +```bash +$ cargo run + Running `target/debug/hello_world` +Hello, world! +``` + +Notice that we didn’t re-build the project this time. Cargo figured out that +we hadn’t changed the source file, and so it just ran the binary. If we had +made a modification, we would have seen it do both: + +```bash +$ cargo build + Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) + Running `target/debug/hello_world` +Hello, world! +``` + +This hasn’t bought us a whole lot over our simple use of `rustc`, but think +about the future: when our project gets more complex, we would need to do more +things to get all of the parts to properly compile. With Cargo, as our project +grows, we can just `cargo build`, and it’ll work the right way. + +When your project is finally ready for release, you can use +`cargo build --release` to compile your project with optimizations. You'll also notice that Cargo has created a new file: `Cargo.lock`. @@ -100,18 +112,25 @@ version = "0.0.1" ``` This file is used by Cargo to keep track of dependencies in your application. -Right now, we don't have any, so it's a bit sparse. You won't ever need +Right now, we don’t have any, so it’s a bit sparse. You won't ever need to touch this file yourself, just let Cargo handle it. -That's it! We've successfully built `hello_world` with Cargo. Even though our -program is simple, it's using much of the real tooling that you'll use for the -rest of your Rust career. +That’s it! We’ve successfully built `hello_world` with Cargo. Even though our +program is simple, it’s using much of the real tooling that you’ll use for the +rest of your Rust career. You can expect to do this to get started with +virtually all Rust projects: + +```bash +$ git clone someurl.com/foo +$ cd foo +$ cargo build +``` ## A New Project -You don't have to go through this whole process every time you want to start a new -project! Cargo has the ability to make a bare-bones project directory in which you -can start developing right away. +You don’t have to go through this whole process every time you want to start a +new project! Cargo has the ability to make a bare-bones project directory in +which you can start developing right away. To start a new project with Cargo, use `cargo new`: @@ -119,8 +138,8 @@ To start a new project with Cargo, use `cargo new`: $ cargo new hello_world --bin ``` -We're passing `--bin` because we're making a binary program: if we -were making a library, we'd leave it off. +We’re passing `--bin` because we're making a binary program: if we were making +a library, we'd leave it off. Let's check out what Cargo has generated for us: @@ -135,10 +154,10 @@ $ tree . 1 directory, 2 files ``` -If you don't have the `tree` command, you can probably get it from your distro's package -manager. It's not necessary, but it's certainly useful. +If you don't have the `tree` command, you can probably get it from your +distribution’s package manager. It’s not necessary, but it’s certainly useful. -This is all we need to get started. First, let's check out `Cargo.toml`: +This is all we need to get started. First, let’s check out `Cargo.toml`: ```toml [package] @@ -148,11 +167,11 @@ version = "0.0.1" authors = ["Your Name "] ``` -Cargo has populated this file with reasonable defaults based off the arguments you gave -it and your `git` global configuration. You may notice that Cargo has also initialized -the `hello_world` directory as a `git` repository. +Cargo has populated this file with reasonable defaults based off the arguments +you gave it and your `git` global configuration. You may notice that Cargo has +also initialized the `hello_world` directory as a `git` repository. -Here's what's in `src/main.rs`: +Here’s what’s in `src/main.rs`: ```rust fn main() { @@ -160,9 +179,20 @@ fn main() { } ``` -Cargo has generated a "Hello World!" for us, and you're ready to start coding! A -much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). +Cargo has generated a "Hello World!" for us, and you’re ready to start coding! Cargo +has its own [guide][guide] which covers Cargo’s features in much more depth. -Now that you've got the tools down, let's actually learn more about the Rust +[guide]: http://doc.crates.io/guide.html + +Now that you’ve got the tools down, let’s actually learn more about the Rust language itself. These are the basics that will serve you well through the rest of your time with Rust. + +You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or +start from the bottom and work your way up with ‘[Syntax and +Semantics][syntax]’. More experienced systems programmers will probably prefer +‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different +people learn differently! Choose whatever’s right for you. + +[learnrust]: learn-rust.html +[syntax]: syntax-and-semantics.html diff --git a/src/doc/trpl/hello-world.md b/src/doc/trpl/hello-world.md index a3b5d655fa..e58bac656d 100644 --- a/src/doc/trpl/hello-world.md +++ b/src/doc/trpl/hello-world.md @@ -1,9 +1,9 @@ % Hello, world! -Now that you have Rust installed, let's write your first Rust program. It's +Now that you have Rust installed, let’s write your first Rust program. It’s traditional to make your first program in any new language one that prints the -text "Hello, world!" to the screen. The nice thing about starting with such a -simple program is that you can verify that your compiler isn't just installed, +text “Hello, world!” to the screen. The nice thing about starting with such a +simple program is that you can verify that your compiler isn’t just installed, but also working properly. And printing information to the screen is a pretty common thing to do. @@ -12,38 +12,37 @@ to make a `projects` directory in my home directory, and keep all my projects there. Rust does not care where your code lives. This actually leads to one other concern we should address: this guide will -assume that you have basic familiarity with the command line. Rust does not -require that you know a whole ton about the command line, but until the -language is in a more finished state, IDE support is spotty. Rust makes no -specific demands on your editing tooling, or where your code lives. +assume that you have basic familiarity with the command line. Rust itself makes +no specific demands on your editing tooling, or where your code lives. If you +prefer an IDE to the command line, you may want to check out +[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are +a number of extensions of varying quality in development by the community. The +Rust team also ships [plugins for various editors][plugins]. Configuring your +editor or IDE is out of the scope of this tutorial, so check the documentation +for your setup, specifically. -With that said, let's make a directory in our projects directory. +[solidoak]: https://github.com/oakes/SolidOak +[plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md -```{bash} +With that said, let’s make a directory in our projects directory. + +```bash $ mkdir ~/projects $ cd ~/projects $ mkdir hello_world $ cd hello_world ``` -If you're on Windows and not using PowerShell, the `~` may not work. Consult +If you’re on Windows and not using PowerShell, the `~` may not work. Consult the documentation for your shell for more details. -Let's make a new source file next. I'm going to use the syntax `editor -filename` to represent editing a file in these examples, but you should use -whatever method you want. We'll call our file `main.rs`: - -```{bash} -$ editor main.rs -``` - -Rust files always end in a `.rs` extension. If you're using more than one word -in your filename, use an underscore. `hello_world.rs` rather than -`helloworld.rs`. +Let’s make a new source file next. We’ll call our file `main.rs`. Rust files +always end in a `.rs` extension. If you’re using more than one word in your +filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`. -Now that you've got your file open, type this in: +Now that you’ve got your file open, type this in: -```{rust} +```rust fn main() { println!("Hello, world!"); } @@ -51,87 +50,90 @@ fn main() { Save the file, and then type this into your terminal window: -```{bash} +```bash $ rustc main.rs $ ./main # or main.exe on Windows Hello, world! ``` -You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code. - -Success! Let's go over what just happened in detail. +Success! Let’s go over what just happened in detail. -```{rust} +```rust fn main() { } ``` These lines define a *function* in Rust. The `main` function is special: -it's the beginning of every Rust program. The first line says "I'm declaring a -function named `main`, which takes no arguments and returns nothing." If there +it's the beginning of every Rust program. The first line says "I’m declaring a +function named `main` which takes no arguments and returns nothing." If there were arguments, they would go inside the parentheses (`(` and `)`), and because -we aren't returning anything from this function, we can omit the return type -entirely. We'll get to it later. +we aren’t returning anything from this function, we can omit the return type +entirely. We’ll get to it later. -You'll also note that the function is wrapped in curly braces (`{` and `}`). +You’ll also note that the function is wrapped in curly braces (`{` and `}`). Rust requires these around all function bodies. It is also considered good style to put the opening curly brace on the same line as the function declaration, with one space in between. Next up is this line: -```{rust} +```rust println!("Hello, world!"); ``` This line does all of the work in our little program. There are a number of -details that are important here. The first is that it's indented with four +details that are important here. The first is that it’s indented with four spaces, not tabs. Please configure your editor of choice to insert four spaces with the tab key. We provide some [sample configurations for various -editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md). +editors][configs]. + +[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md -The second point is the `println!()` part. This is calling a Rust *macro*, +The second point is the `println!()` part. This is calling a Rust [macro][macro], which is how metaprogramming is done in Rust. If it were a function instead, it -would look like this: `println()`. For our purposes, we don't need to worry -about this difference. Just know that sometimes, you'll see a `!`, and that -means that you're calling a macro instead of a normal function. Rust implements -`println!` as a macro rather than a function for good reasons, but that's a -very advanced topic. You'll learn more when we talk about macros later. One -last thing to mention: Rust's macros are significantly different from C macros, -if you've used those. Don't be scared of using macros. We'll get to the details -eventually, you'll just have to trust us for now. - -Next, `"Hello, world!"` is a *string*. Strings are a surprisingly complicated -topic in a systems programming language, and this is a *statically allocated* -string. We will talk more about different kinds of allocation later. We pass -this string as an argument to `println!`, which prints the string to the -screen. Easy enough! - -Finally, the line ends with a semicolon (`;`). Rust is an *expression -oriented* language, which means that most things are expressions. 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 `;`. We will cover this in-depth -later in the guide. - -Finally, actually *compiling* and *running* our program. We can compile -with our compiler, `rustc`, by passing it the name of our source file: - -```{bash} +would look like this: `println()`. For our purposes, we don’t need to worry +about this difference. Just know that sometimes, you’ll see a `!`, and that +means that you’re calling a macro instead of a normal function. Rust implements +`println!` as a macro rather than a function for good reasons, but that's an +advanced topic. One last thing to mention: Rust’s macros are significantly +different from C macros, if you’ve used those. Don’t be scared of using macros. +We’ll get to the details eventually, you’ll just have to trust us for now. + +[macro]: macros.html + +Next, `"Hello, world!"` is a ‘string’. Strings are a surprisingly complicated +topic in a systems programming language, and this is a ‘statically allocated’ +string. If you want to read further about allocation, check out +[the stack and the heap][allocation], but you don’t need to right now if you +don’t want to. We pass this string as an argument to `println!`, which prints the +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, actually compiling and running our program. We can compile with our +compiler, `rustc`, by passing it the name of our source file: + +```bash $ rustc main.rs ``` This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust will output a binary executable. You can see it with `ls`: -```{bash} +```bash $ ls main main.rs ``` Or on Windows: -```{bash} +```bash $ dir main.exe main.rs ``` @@ -139,7 +141,7 @@ main.exe main.rs There are now two files: our source code, with the `.rs` extension, and the executable (`main.exe` on Windows, `main` everywhere else) -```{bash} +```bash $ ./main # or main.exe on Windows ``` @@ -147,15 +149,15 @@ This prints out our `Hello, world!` text to our terminal. If you come from a dynamically typed language like Ruby, Python, or JavaScript, you may not be used to these two steps being separate. Rust is an -*ahead-of-time compiled language*, which means that you can compile a -program, give it to someone else, and they don't need to have Rust installed. -If you give someone a `.rb` or `.py` or `.js` file, they need to have -Ruby/Python/JavaScript installed, but you just need one command to both compile -and run your program. Everything is a tradeoff in language design, and Rust has -made its choice. +‘ahead-of-time compiled language’, which means that you can compile a program, +give it to someone else, and they don't need to have Rust installed. If you +give someone a `.rb` or `.py` or `.js` file, they need to have a +Ruby/Python/JavaScript implementation installed, but you just need one command +to both compile and run your program. Everything is a tradeoff in language +design, and Rust has made its choice. Congratulations! You have officially written a Rust program. That makes you a -Rust programmer! Welcome. +Rust programmer! Welcome. 🎊🎉👍 Next, I'd like to introduce you to another tool, Cargo, which is used to write real-world Rust programs. Just using `rustc` is nice for simple things, but as diff --git a/src/doc/trpl/if-let.md b/src/doc/trpl/if-let.md new file mode 100644 index 0000000000..9e010b020c --- /dev/null +++ b/src/doc/trpl/if-let.md @@ -0,0 +1,3 @@ +% if let + +COMING SOON diff --git a/src/doc/trpl/if.md b/src/doc/trpl/if.md index 7dac49987d..a532dabf8d 100644 --- a/src/doc/trpl/if.md +++ b/src/doc/trpl/if.md @@ -1,10 +1,10 @@ -% If +% if -Rust's take on `if` is not particularly complex, but it's much more like the -`if` you'll find in a dynamically typed language than in a more traditional -systems language. So let's talk about it, to make sure you grasp the nuances. +Rust’s take on `if` is not particularly complex, but it’s much more like the +`if` you’ll find in a dynamically typed language than in a more traditional +systems language. So let’s talk about it, to make sure you grasp the nuances. -`if` is a specific form of a more general concept, the *branch*. The name comes +`if` is a specific form of a more general concept, the ‘branch’. The name comes from a branch in a tree: a decision point, where depending on a choice, multiple paths can be taken. @@ -20,11 +20,11 @@ if x == 5 { If we changed the value of `x` to something else, this line would not print. More specifically, if the expression after the `if` evaluates to `true`, then -the block is executed. If it's `false`, then it is not. +the block is executed. If it’s `false`, then it is not. If you want something to happen in the `false` case, use an `else`: -```{rust} +```rust let x = 5; if x == 5 { @@ -50,8 +50,7 @@ if x == 5 { This is all pretty standard. However, you can also do this: - -```{rust} +```rust let x = 5; let y = if x == 5 { @@ -63,93 +62,12 @@ let y = if x == 5 { Which we can (and probably should) write like this: -```{rust} +```rust let x = 5; let y = if x == 5 { 10 } else { 15 }; // y: i32 ``` -This reveals two interesting things about Rust: it is an expression-based -language, and semicolons are different from semicolons in other 'curly brace -and semicolon'-based languages. These two things are related. - -## Expressions vs. Statements - -Rust is primarily an expression based language. There are only two kinds of -statements, and everything else is an expression. - -So what's the difference? Expressions return a value, and statements do not. -In many languages, `if` is a statement, and therefore, `let x = if ...` would -make no sense. But in Rust, `if` is an expression, which means that it returns -a value. We can then use this value to initialize the binding. - -Speaking of which, bindings are a kind of the first of Rust's two statements. -The proper name is a *declaration statement*. So far, `let` is the only kind -of declaration statement we've seen. Let's talk about that some more. - -In some languages, variable bindings can be written as expressions, not just -statements. Like Ruby: - -```{ruby} -x = y = 5 -``` - -In Rust, however, using `let` to introduce a binding is _not_ an expression. The -following will produce a compile-time error: - -```{ignore} -let x = (let y = 5); // expected identifier, found keyword `let` -``` - -The compiler is telling us here that it was expecting to see the beginning of -an expression, and a `let` can only begin a statement, not an expression. - -Note that assigning to an already-bound variable (e.g. `y = 5`) is still an -expression, although its value is not particularly useful. Unlike C, where an -assignment evaluates to the assigned value (e.g. `5` in the previous example), -in Rust the value of an assignment is the unit type `()` (which we'll cover later). - -The second kind of statement in Rust is the *expression statement*. Its -purpose is to turn any expression into a statement. In practical terms, Rust's -grammar expects statements to follow other statements. This means that you use -semicolons to separate expressions from each other. This means that Rust -looks a lot like most other languages that require you to use semicolons -at the end of every line, and you will see semicolons at the end of almost -every line of Rust code you see. - -What is this exception that makes us say "almost"? You saw it already, in this -code: - -```{rust} -let x = 5; - -let y: i32 = if x == 5 { 10 } else { 15 }; -``` - -Note that I've added the type annotation to `y`, to specify explicitly that I -want `y` to be an integer. - -This is not the same as this, which won't compile: - -```{ignore} -let x = 5; - -let y: i32 = if x == 5 { 10; } else { 15; }; -``` - -Note the semicolons after the 10 and 15. Rust will give us the following error: - -```text -error: mismatched types: expected `i32`, found `()` (expected i32, found ()) -``` - -We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a -special type in Rust's type system. In Rust, `()` is _not_ a valid value for a -variable of type `i32`. It's only a valid value for variables of the type `()`, -which aren't very useful. Remember how we said statements don't return a value? -Well, that's the purpose of unit in this case. The semicolon turns any -expression into a statement by throwing away its value and returning unit -instead. - -There's one more time in which you won't see a semicolon at the end of a line -of Rust code. For that, we'll need our next concept: functions. +This works because `if` is an expression. The value of the expression is the +value of the last expression in whichever branch was chosen. An `if` without an +`else` always results in `()` as the value. diff --git a/src/doc/trpl/installing-rust.md b/src/doc/trpl/installing-rust.md index 288a4a158f..09b4495ffe 100644 --- a/src/doc/trpl/installing-rust.md +++ b/src/doc/trpl/installing-rust.md @@ -1,27 +1,32 @@ % Installing Rust 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 (note that you don't need to type -in the `$`s, they just indicate the start of each command): +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 (note that you don't need to type in the +`$`s, they just indicate the start of each command): ```bash $ curl -sf -L https://static.rust-lang.org/rustup.sh | sudo sh ``` -If you're concerned about the [potential insecurity](http://curlpipesh.tumblr.com/) of using `curl | sudo sh`, -please keep reading and see our disclaimer below. And feel free to use a two-step version of the installation and examine our installation script: +If you're concerned about the [potential insecurity][insecurity] of using `curl +| sudo sh`, please keep reading and see our disclaimer below. And feel free to +use a two-step version of the installation and examine our installation script: ```bash $ curl -f -L https://static.rust-lang.org/rustup.sh -O $ sudo sh rustup.sh ``` -If you're on Windows, please download either the [32-bit -installer](https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.exe) -or the [64-bit -installer](https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.exe) -and run it. +[insecurity]: http://curlpipesh.tumblr.com + +If you're on Windows, please download either the [32-bit installer][win32] or +the [64-bit installer][win64] and run it. + +[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi +[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi + +## Uninstalling If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. Not every programming language is great for everyone. Just run the uninstall @@ -31,22 +36,20 @@ script: $ sudo /usr/local/lib/rustlib/uninstall.sh ``` -If you used the Windows installer, just re-run the `.exe` and it will give you +If you used the Windows installer, just re-run the `.msi` and it will give you an uninstall option. -You can re-run this script any time you want to update Rust. Which, at this -point, is often. Rust is still pre-1.0, and so people assume that you're using -a very recent Rust. +Some people, and somewhat rightfully so, get very upset when we tell you to +`curl | sudo 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. +That's a good instinct! If you're one of those people, please check out the +documentation on [building Rust from Source][from source], or [the official +binary downloads][install page]. And we promise that this method will not be +the way to install Rust forever: it's just the easiest way to keep people +updated while Rust is in its alpha state. -This brings me to one other point: some people, and somewhat rightfully so, get -very upset when we tell you to `curl | sudo sh`. And they should be! 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. That's a good instinct! -If you're one of those people, please check out the documentation on [building -Rust from Source](https://github.com/rust-lang/rust#building-from-source), or -[the official binary downloads](http://www.rust-lang.org/install.html). And we -promise that this method will not be the way to install Rust forever: it's just -the easiest way to keep people updated while Rust is in its alpha state. +[from source]: https://github.com/rust-lang/rust#building-from-source +[install page]: http://www.rust-lang.org/install.html Oh, we should also mention the officially supported platforms: @@ -73,7 +76,7 @@ $ rustc --version You should see the version number, commit hash, commit date and build date: ```bash -rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06) +rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02) ``` If you did, Rust has been installed successfully! Congrats! @@ -84,10 +87,13 @@ On Windows, it's in a `share/doc` directory, inside wherever you installed Rust to. If not, there are a number of places where you can get help. The easiest is -[the #rust IRC channel on irc.mozilla.org](irc://irc.mozilla.org/#rust), which -you can access through -[Mibbit](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust). Click -that link, and you'll be chatting with other Rustaceans (a silly nickname we -call ourselves), and we can help you out. Other great resources include [the -/r/rust subreddit](http://www.reddit.com/r/rust), and [Stack -Overflow](http://stackoverflow.com/questions/tagged/rust). +[the #rust IRC channel on irc.mozilla.org][irc], which you can access through +[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans +(a silly nickname we call ourselves), and we can help you out. Other great +resources include [the user’s forum][users], and +[Stack Overflow][stack overflow]. + +[irc]: irc://irc.mozilla.org/#rust +[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[users]: http://users.rust-lang.org/ +[stack overflow]: http://stackoverflow.com/questions/tagged/rust diff --git a/src/doc/trpl/intermediate.md b/src/doc/trpl/intermediate.md deleted file mode 100644 index 73370a3223..0000000000 --- a/src/doc/trpl/intermediate.md +++ /dev/null @@ -1,7 +0,0 @@ -% Intermediate - -This section contains individual chapters, which are self-contained. They focus -on specific topics, and can be read in any order. - -After reading "Intermediate," you will have a solid understanding of Rust, -and will be able to understand most Rust code and write more complex programs. diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index 55776bee3b..eea575658b 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -291,7 +291,7 @@ If you are trying to execute a closure on an iterator for its side effects, just use `for` instead. There are tons of interesting iterator adapters. `take(n)` will return an -iterator over the next `n` elements of the original iterator, note that this +iterator over the next `n` elements of the original iterator. Note that this has no side effect on the original iterator. Let's try it out with our infinite iterator from before: diff --git a/src/doc/trpl/learn-rust.md b/src/doc/trpl/learn-rust.md new file mode 100644 index 0000000000..3d8ef8090b --- /dev/null +++ b/src/doc/trpl/learn-rust.md @@ -0,0 +1,4 @@ +% Learn Rust + +This section is coming soon! It will eventually have a few tutorials with +building real Rust projects, but they are under development. diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md new file mode 100644 index 0000000000..c6eee97dc6 --- /dev/null +++ b/src/doc/trpl/lifetimes.md @@ -0,0 +1,3 @@ +% Lifetimes + +Coming soon! diff --git a/src/doc/trpl/looping.md b/src/doc/trpl/looping.md deleted file mode 100644 index 28f02b1ffe..0000000000 --- a/src/doc/trpl/looping.md +++ /dev/null @@ -1,133 +0,0 @@ -% Looping - -Looping is the last basic construct that we haven't learned yet in Rust. Rust has -two main looping constructs: `for` and `while`. - -## `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, which we will discuss in more depth later in the -guide. 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. - -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. - -We'll talk more about `for` when we cover *iterators*, later in the Guide. - -## `while` - -The other kind of looping construct in Rust is the `while` loop. It looks like -this: - -```{rust} -let mut x = 5; // mut x: u32 -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. The details of what -that _means_ aren't super important to understand at this stage, but 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 kinds of loops. diff --git a/src/doc/trpl/macros.md b/src/doc/trpl/macros.md index 7e19ec94ee..6d21cb5938 100644 --- a/src/doc/trpl/macros.md +++ b/src/doc/trpl/macros.md @@ -424,9 +424,240 @@ they are unstable and require feature gates. * `trace_macros!(true)` will enable a compiler message every time a macro is expanded. Use `trace_macros!(false)` later in expansion to turn it off. -# Further reading +# Syntactic requirements -The [advanced macros chapter][] goes into more detail about macro syntax. It -also describes how to share macros between different modules or crates. +Even when Rust code contains un-expanded macros, it can be parsed as a full +[syntax tree][ast]. This property can be very useful for editors and other +tools that process code. It also has a few consequences for the design of +Rust's macro system. -[advanced macros chapter]: advanced-macros.html +[ast]: glossary.html#abstract-syntax-tree + +One consequence is that Rust must determine, when it parses a macro invocation, +whether the macro stands in for + +* zero or more items, +* zero or more methods, +* an expression, +* a statement, or +* a pattern. + +A macro invocation within a block could stand for some items, or for an +expression / statement. Rust uses a simple rule to resolve this ambiguity. A +macro invocation that stands for items must be either + +* delimited by curly braces, e.g. `foo! { ... }`, or +* terminated by a semicolon, e.g. `foo!(...);` + +Another consequence of pre-expansion parsing is that the macro invocation must +consist of valid Rust tokens. Furthermore, parentheses, brackets, and braces +must be balanced within a macro invocation. For example, `foo!([)` is +forbidden. This allows Rust to know where the macro invocation ends. + +More formally, the macro invocation body must be a sequence of *token trees*. +A token tree is defined recursively as either + +* a sequence of token trees surrounded by matching `()`, `[]`, or `{}`, or +* any other single token. + +Within a matcher, each metavariable has a *fragment specifier*, identifying +which syntactic form it matches. + +* `ident`: an identifier. Examples: `x`; `foo`. +* `path`: a qualified name. Example: `T::SpecialA`. +* `expr`: an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`; `f(42)`. +* `ty`: a type. Examples: `i32`; `Vec<(char, String)>`; `&T`. +* `pat`: a pattern. Examples: `Some(t)`; `(17, 'a')`; `_`. +* `stmt`: a single statement. Example: `let x = 3`. +* `block`: a brace-delimited sequence of statements. Example: + `{ log(error, "hi"); return 12; }`. +* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`. +* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`. +* `tt`: a single token tree. + +There are additional rules regarding the next token after a metavariable: + +* `expr` variables must be followed by one of: `=> , ;` +* `ty` and `path` variables must be followed by one of: `=> , : = > as` +* `pat` variables must be followed by one of: `=> , =` +* Other variables may be followed by any token. + +These rules provide some flexibility for Rust's syntax to evolve without +breaking existing macros. + +The macro system does not deal with parse ambiguity at all. For example, the +grammar `$($t:ty)* $e:expr` will always fail to parse, because the parser would +be forced to choose between parsing `$t` and parsing `$e`. Changing the +invocation syntax to put a distinctive token in front can solve the problem. In +this case, you can write `$(T $t:ty)* E $e:exp`. + +[item]: ../reference.html#items + +# Scoping and macro import/export + +Macros are expanded at an early stage in compilation, before name resolution. +One downside is that scoping works differently for macros, compared to other +constructs in the language. + +Definition and expansion of macros both happen in a single depth-first, +lexical-order traversal of a crate's source. So a macro defined at module scope +is visible to any subsequent code in the same module, which includes the body +of any subsequent child `mod` items. + +A macro defined within the body of a single `fn`, or anywhere else not at +module scope, is visible only within that item. + +If a module has the `macro_use` attribute, its macros are also visible in its +parent module after the child's `mod` item. If the parent also has `macro_use` +then the macros will be visible in the grandparent after the parent's `mod` +item, and so forth. + +The `macro_use` attribute can also appear on `extern crate`. In this context +it controls which macros are loaded from the external crate, e.g. + +```rust,ignore +#[macro_use(foo, bar)] +extern crate baz; +``` + +If the attribute is given simply as `#[macro_use]`, all macros are loaded. If +there is no `#[macro_use]` attribute then no macros are loaded. Only macros +defined with the `#[macro_export]` attribute may be loaded. + +To load a crate's macros *without* linking it into the output, use `#[no_link]` +as well. + +An example: + +```rust +macro_rules! m1 { () => (()) } + +// visible here: m1 + +mod foo { + // visible here: m1 + + #[macro_export] + macro_rules! m2 { () => (()) } + + // visible here: m1, m2 +} + +// visible here: m1 + +macro_rules! m3 { () => (()) } + +// visible here: m1, m3 + +#[macro_use] +mod bar { + // visible here: m1, m3 + + macro_rules! m4 { () => (()) } + + // visible here: m1, m3, m4 +} + +// visible here: m1, m3, m4 +# fn main() { } +``` + +When this library is loaded with `#[macro_use] extern crate`, only `m2` will +be imported. + +The Rust Reference has a [listing of macro-related +attributes](../reference.html#macro--and-plugin-related-attributes). + +# The variable `$crate` + +A further difficulty occurs when a macro is used in multiple crates. Say that +`mylib` defines + +```rust +pub fn increment(x: u32) -> u32 { + x + 1 +} + +#[macro_export] +macro_rules! inc_a { + ($x:expr) => ( ::increment($x) ) +} + +#[macro_export] +macro_rules! inc_b { + ($x:expr) => ( ::mylib::increment($x) ) +} +# fn main() { } +``` + +`inc_a` only works within `mylib`, while `inc_b` only works outside the +library. Furthermore, `inc_b` will break if the user imports `mylib` under +another name. + +Rust does not (yet) have a hygiene system for crate references, but it does +provide a simple workaround for this problem. Within a macro imported from a +crate named `foo`, the special macro variable `$crate` will expand to `::foo`. +By contrast, when a macro is defined and then used in the same crate, `$crate` +will expand to nothing. This means we can write + +```rust +#[macro_export] +macro_rules! inc { + ($x:expr) => ( $crate::increment($x) ) +} +# fn main() { } +``` + +to define a single macro that works both inside and outside our library. The +function name will expand to either `::increment` or `::mylib::increment`. + +To keep this system simple and correct, `#[macro_use] extern crate ...` may +only appear at the root of your crate, not inside `mod`. This ensures that +`$crate` is a single identifier. + +# The deep end + +The introductory chapter mentioned recursive macros, but it did not give the +full story. Recursive macros are useful for another reason: Each recursive +invocation gives you another opportunity to pattern-match the macro's +arguments. + +As an extreme example, it is possible, though hardly advisable, to implement +the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton +within Rust's macro system. + +```rust +macro_rules! bct { + // cmd 0: d ... => ... + (0, $($ps:tt),* ; $_d:tt) + => (bct!($($ps),*, 0 ; )); + (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) + => (bct!($($ps),*, 0 ; $($ds),*)); + + // cmd 1p: 1 ... => 1 ... p + (1, $p:tt, $($ps:tt),* ; 1) + => (bct!($($ps),*, 1, $p ; 1, $p)); + (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); + + // cmd 1p: 0 ... => 0 ... + (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) + => (bct!($($ps),*, 1, $p ; $($ds),*)); + + // halt on empty data string + ( $($ps:tt),* ; ) + => (()); +} +``` + +Exercise: use macros to reduce duplication in the above definition of the +`bct!` macro. + +# Procedural macros + +If Rust's macro system can't do what you need, you may want to write a +[compiler plugin](plugins.html) instead. Compared to `macro_rules!` +macros, this is significantly more work, the interfaces are much less stable, +and bugs can be much harder to track down. In exchange you get the +flexibility of running arbitrary Rust code within the compiler. Syntax +extension plugins are sometimes called *procedural macros* for this reason. diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 73bc775a1b..33d603f326 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -1,13 +1,13 @@ % Match -Often, a simple `if`/`else` isn't enough, because you have more than two +Often, a simple `if`/`else` isn’t enough, because you have more than two possible options. Also, `else` conditions can get incredibly complicated, so -what's the solution? +what’s the solution? Rust has a keyword, `match`, that allows you to replace complicated `if`/`else` groupings with something more powerful. Check it out: -```{rust} +```rust let x = 5; match x { @@ -21,11 +21,14 @@ match x { ``` `match` takes an expression and then branches based on its value. Each *arm* of -the branch is of the form `val => expression`. When the value matches, that arm's -expression will be evaluated. It's called `match` because of the term 'pattern -matching', which `match` is an implementation of. +the branch is of the form `val => expression`. When the value matches, that arm’s +expression will be evaluated. It’s called `match` because of the term ‘pattern +matching’, which `match` is an implementation of. There’s an [entire section on +patterns][patterns] coming up next, that covers all the options that fit here. -So what's the big advantage here? Well, there are a few. First of all, `match` +[patterns]: patterns.html + +So what’s the big advantage here? Well, there are a few. First of all, `match` enforces *exhaustiveness checking*. Do you see that last arm, the one with the underscore (`_`)? If we remove that arm, Rust will give us an error: @@ -36,121 +39,24 @@ error: non-exhaustive patterns: `_` not covered In other words, Rust is trying to tell us we forgot a value. Because `x` is an integer, Rust knows that it can have a number of different values – for example, `6`. Without the `_`, however, there is no arm that could match, and so Rust refuses -to compile. `_` acts like a *catch-all arm*. If none of the other arms match, +to compile. `_` acts like a ‘catch-all arm’. If none of the other arms match, the arm with `_` will, and since we have this catch-all arm, we now have an arm for every possible value of `x`, and so our program will compile successfully. -`match` statements also destructure enums, as well. Remember this code from the -section on enums? - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - let ordering = cmp(x, y); - - if ordering == Ordering::Less { - println!("less"); - } else if ordering == Ordering::Greater { - println!("greater"); - } else if ordering == Ordering::Equal { - println!("equal"); - } -} -``` - -We can re-write this as a `match`: - -```{rust} -use std::cmp::Ordering; - -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; - - match cmp(x, y) { - Ordering::Less => println!("less"), - Ordering::Greater => println!("greater"), - Ordering::Equal => println!("equal"), - } -} -``` - -This version has way less noise, and it also checks exhaustively to make sure -that we have covered all possible variants of `Ordering`. With our `if`/`else` -version, if we had forgotten the `Greater` case, for example, our program would -have happily compiled. If we forget in the `match`, it will not. Rust helps us -make sure to cover all of our bases. - -`match` expressions also allow us to get the values contained in an `enum` -(also known as destructuring) as follows: - -```{rust} -enum OptionalInt { - Value(i32), - Missing, -} - -fn main() { - let x = OptionalInt::Value(5); - let y = OptionalInt::Missing; - - match x { - OptionalInt::Value(n) => println!("x is {}", n), - OptionalInt::Missing => println!("x is missing!"), - } - - match y { - OptionalInt::Value(n) => println!("y is {}", n), - OptionalInt::Missing => println!("y is missing!"), - } -} -``` - -That is how you can get and use the values contained in `enum`s. -It can also allow us to handle errors or unexpected computations; for example, a -function that is not guaranteed to be able to compute a result (an `i32` here) -could return an `OptionalInt`, and we would handle that value with a `match`. -As you can see, `enum` and `match` used together are quite useful! - `match` is also an expression, which means we can use it on the right-hand -side of a `let` binding or directly where an expression is used. We could -also implement the previous example like this: - -```{rust} -use std::cmp::Ordering; +side of a `let` binding or directly where an expression is used: -fn cmp(a: i32, b: i32) -> Ordering { - if a < b { Ordering::Less } - else if a > b { Ordering::Greater } - else { Ordering::Equal } -} - -fn main() { - let x = 5; - let y = 10; +```rust +let x = 5; - println!("{}", match cmp(x, y) { - Ordering::Less => "less", - Ordering::Greater => "greater", - Ordering::Equal => "equal", - }); -} +let numer = match x { + 1 => "one", + 2 => "two", + 3 => "three", + 4 => "four", + 5 => "five", + _ => "something else", +}; ``` -Sometimes, it's a nice pattern. +Sometimes, it’s a nice way of converting things. diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index 18542e58bb..ae83a930a1 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -4,7 +4,7 @@ Functions are great, but if you want to call a bunch of them on some data, it can be awkward. Consider this code: ```{rust,ignore} -baz(bar(foo(x))); +baz(bar(foo))); ``` We would read this left-to right, and so we see "baz bar foo." But this isn't the @@ -12,7 +12,7 @@ order that the functions would get called in, that's inside-out: "foo bar baz." Wouldn't it be nice if we could do this instead? ```{rust,ignore} -x.foo().bar().baz(); +foo.bar().baz(); ``` Luckily, as you may have guessed with the leading question, you can! Rust provides @@ -47,8 +47,8 @@ This will print `12.566371`. We've made a struct that represents a circle. We then write an `impl` block, and inside it, define a method, `area`. Methods take a special first parameter, of which there are three variants: `self`, `&self`, and `&mut self`. -You can think of this first parameter as being the `x` in `x.foo()`. The three -variants correspond to the three kinds of thing `x` could be: `self` if it's +You can think of this first parameter as being the `foo` in `foo.bar()`. The three +variants correspond to the three kinds of things `foo` could be: `self` if it's just a value on the stack, `&self` if it's a reference, and `&mut self` if it's a mutable reference. We should default to using `&self`, as you should prefer borrowing over taking ownership, as well as taking immutable references @@ -197,7 +197,7 @@ impl CircleBuilder { } fn y(&mut self, coordinate: f64) -> &mut CircleBuilder { - self.x = coordinate; + self.y = coordinate; self } diff --git a/src/doc/trpl/more-strings.md b/src/doc/trpl/more-strings.md deleted file mode 100644 index 17a463842e..0000000000 --- a/src/doc/trpl/more-strings.md +++ /dev/null @@ -1,325 +0,0 @@ -% More Strings - -Strings are an important concept to master in any programming language. If you -come from a managed language background, you may be surprised at the complexity -of string handling in a systems programming language. Efficient access and -allocation of memory for a dynamically sized structure involves a lot of -details. Luckily, Rust has lots of tools to help us here. - -A **string** is a sequence of unicode scalar values encoded as a stream of -UTF-8 bytes. All strings are guaranteed to be validly-encoded UTF-8 sequences. -Additionally, strings are not null-terminated and can contain null bytes. - -Rust has two main types of strings: `&str` and `String`. - -# `&str` - -The first kind is a `&str`. This is pronounced a 'string slice'. -String literals are of the type `&str`: - -``` -let string = "Hello there."; -``` - -Like any Rust reference, string slices have an associated lifetime. A string -literal is a `&'static str`. A string slice can be written without an explicit -lifetime in many cases, such as in function arguments. In these cases the -lifetime will be inferred: - -``` -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} -``` - -Like vector slices, string slices are simply a pointer plus a length. This -means that they're a 'view' into an already-allocated string, such as a -string literal or a `String`. - -## `str` - -You may occasionally see references to a `str` type, without the `&`. While -this type does exist, it’s not something you want to use yourself. Sometimes, -people confuse `str` for `String`, and write this: - -```rust -struct S { - s: str, -} -``` - -This leads to ugly errors: - -```text -error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277] -note: `str` does not have a constant size known at compile-time -``` - -Instead, this `struct` should be - -```rust -struct S { - s: String, -} -``` - -So let’s talk about `String`s. - -# `String` - -A `String` is a heap-allocated string. This string is growable, and is -also guaranteed to be UTF-8. `String`s are commonly created by -converting from a string slice using the `to_string` method. - -``` -let mut s = "Hello".to_string(); -println!("{}", s); - -s.push_str(", world."); -println!("{}", s); -``` - -A reference to a `String` will automatically coerce to a string slice: - -``` -fn takes_slice(slice: &str) { - println!("Got: {}", slice); -} - -fn main() { - let s = "Hello".to_string(); - takes_slice(&s); -} -``` - -You can also get a `&str` from a stack-allocated array of bytes: - -``` -use std::str; - -let x: &[u8] = &[b'a', b'b']; -let stack_str: &str = str::from_utf8(x).unwrap(); -``` - -# Best Practices - -## `String` vs. `&str` - -In general, you should prefer `String` when you need ownership, and `&str` when -you just need to borrow a string. This is very similar to using `Vec` vs. `&[T]`, -and `T` vs `&T` in general. - -This means starting off with this: - -```{rust,ignore} -fn foo(s: &str) { -``` - -and only moving to this: - -```{rust,ignore} -fn foo(s: String) { -``` - -if you have good reason. It's not polite to hold on to ownership you don't -need, and it can make your lifetimes more complex. - -## Generic functions - -To write a function that's generic over types of strings, use `&str`. - -``` -fn some_string_length(x: &str) -> usize { - x.len() -} - -fn main() { - let s = "Hello, world"; - - println!("{}", some_string_length(s)); - - let s = "Hello, world".to_string(); - - println!("{}", some_string_length(&s)); -} -``` - -Both of these lines will print `12`. - -## Indexing strings - -You may be tempted to try to access a certain character of a `String`, like -this: - -```{rust,ignore} -let s = "hello".to_string(); - -println!("{}", s[0]); -``` - -This does not compile. This is on purpose. In the world of UTF-8, direct -indexing is basically never what you want to do. The reason is that each -character can be a variable number of bytes. This means that you have to iterate -through the characters anyway, which is an O(n) operation. - -There's 3 basic levels of unicode (and its encodings): - -- code units, the underlying data type used to store everything -- code points/unicode scalar values (char) -- graphemes (visible characters) - -Rust provides iterators for each of these situations: - -- `.bytes()` will iterate over the underlying bytes -- `.chars()` will iterate over the code points -- `.graphemes()` will iterate over each grapheme - -Usually, the `graphemes()` method on `&str` is what you want: - -``` -# #![feature(unicode)] -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.graphemes(true) { - println!("{}", l); -} -``` - -This prints: - -```text -u͔ -n͈̰̎ -i̙̮͚̦ -c͚̉ -o̼̩̰͗ -d͔̆̓ͥ -é -``` - -Note that `l` has the type `&str` here, since a single grapheme can consist of -multiple codepoints, so a `char` wouldn't be appropriate. - -This will print out each visible character in turn, as you'd expect: first `u͔`, then -`n͈̰̎`, etc. If you wanted each individual codepoint of each grapheme, you can use `.chars()`: - -``` -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.chars() { - println!("{}", l); -} -``` - -This prints: - -```text -u -͔ -n -̎ -͈ -Ì° -i -̙ -Ì® -͚ -̦ -c -̉ -͚ -o -͗ -̼ -Ì© -Ì° -d -̆ -̓ -Í¥ -͔ -e -́ -``` - -You can see how some of them are combining characters, and therefore the output -looks a bit odd. - -If you want the individual byte representation of each codepoint, you can use -`.bytes()`: - -``` -let s = "u͔n͈̰̎i̙̮͚̦c͚̉o̼̩̰͗d͔̆̓ͥé"; - -for l in s.bytes() { - println!("{}", l); -} -``` - -This will print: - -```text -117 -205 -148 -110 -204 -142 -205 -136 -204 -176 -105 -204 -153 -204 -174 -205 -154 -204 -166 -99 -204 -137 -205 -154 -111 -205 -151 -204 -188 -204 -169 -204 -176 -100 -204 -134 -205 -131 -205 -165 -205 -148 -101 -204 -129 -``` - -Many more bytes than graphemes! - -# `Deref` coercions - -References to `String`s will automatically coerce into `&str`s. Like this: - -``` -fn hello(s: &str) { - println!("Hello, {}!", s); -} - -let slice = "Steve"; -let string = "Steve".to_string(); - -hello(slice); -hello(&string); -``` diff --git a/src/doc/trpl/move-semantics.md b/src/doc/trpl/move-semantics.md new file mode 100644 index 0000000000..6917d7f8b8 --- /dev/null +++ b/src/doc/trpl/move-semantics.md @@ -0,0 +1,3 @@ +% Move Semantics + +Coming Soon diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md new file mode 100644 index 0000000000..ccb03c7f85 --- /dev/null +++ b/src/doc/trpl/mutability.md @@ -0,0 +1,3 @@ +% Mutability + +Coming Soon diff --git a/src/doc/trpl/nightly-rust.md b/src/doc/trpl/nightly-rust.md new file mode 100644 index 0000000000..3b76cce568 --- /dev/null +++ b/src/doc/trpl/nightly-rust.md @@ -0,0 +1,102 @@ +% Nightly Rust + +Rust provides three distribution channels for Rust: nightly, beta, and stable. +Unstable features are only available on nightly Rust. For more details on this +process, see ‘[Stability as a deliverable][stability]’. + +[stability]: http://blog.rust-lang.org/2014/10/30/Stability.html + +To install nightly Rust, you can use `rustup.sh`: + +```bash +$ curl -s https://static.rust-lang.org/rustup.sh | sudo sh -s -- --channel=nightly +``` + +If you're concerned about the [potential insecurity][insecurity] of using `curl +| sudo sh`, please keep reading and see our disclaimer below. And feel free to +use a two-step version of the installation and examine our installation script: + +```bash +$ curl -f -L https://static.rust-lang.org/rustup.sh -O +$ sudo sh rustup.sh --channel=nightly +``` + +[insecurity]: http://curlpipesh.tumblr.com + +If you're on Windows, please download either the [32-bit installer][win32] or +the [64-bit installer][win64] and run it. + +[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi +[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi + +## Uninstalling + +If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay. +Not every programming language is great for everyone. Just run the uninstall +script: + +```bash +$ 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. + +Some people, and somewhat rightfully so, get very upset when we tell you to +`curl | sudo 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. +That's a good instinct! If you're one of those people, please check out the +documentation on [building Rust from Source][from source], or [the official +binary downloads][install page]. And we promise that this method will not be +the way to install Rust forever: it's just the easiest way to keep people +updated while Rust is in its alpha state. + +[from source]: https://github.com/rust-lang/rust#building-from-source +[install page]: http://www.rust-lang.org/install.html + +Oh, we should also mention the officially supported platforms: + +* Windows (7, 8, Server 2008 R2) +* Linux (2.6.18 or later, various distributions), x86 and x86-64 +* OSX 10.7 (Lion) or greater, x86 and x86-64 + +We extensively test Rust on these platforms, and a few others, too, like +Android. But these are the ones most likely to work, as they have the most +testing. + +Finally, a comment about Windows. Rust considers Windows to be a first-class +platform upon release, but if we're honest, the Windows experience isn't as +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. + +If you've got Rust installed, you can open up a shell, and type this: + +```bash +$ rustc --version +``` + +You should see the version number, commit hash, commit date and build date: + +```bash +rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06) +``` + +If you did, Rust has been installed successfully! Congrats! + +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 +to. + +If not, there are a number of places where you can get help. The easiest is +[the #rust IRC channel on irc.mozilla.org][irc], which you can access through +[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans +(a silly nickname we call ourselves), and we can help you out. Other great +resources include [the user’s forum][users], and [Stack Overflow][stack +overflow]. + +[irc]: irc://irc.mozilla.org/#rust +[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust +[users]: http://users.rust-lang.org/ +[stack overflow]: http://stackoverflow.com/questions/tagged/rust diff --git a/src/doc/trpl/no-stdlib.md b/src/doc/trpl/no-stdlib.md index 094c82a08c..67db919c59 100644 --- a/src/doc/trpl/no-stdlib.md +++ b/src/doc/trpl/no-stdlib.md @@ -103,7 +103,7 @@ necessary functionality for writing idiomatic and effective Rust code. As an example, here is a program that will calculate the dot product of two vectors provided from C, using idiomatic Rust practices. -``` +```ignore #![feature(lang_items, start, no_std, core, libc)] #![no_std] diff --git a/src/doc/trpl/operators-and-overloading.md b/src/doc/trpl/operators-and-overloading.md new file mode 100644 index 0000000000..f6f9d5cae1 --- /dev/null +++ b/src/doc/trpl/operators-and-overloading.md @@ -0,0 +1,3 @@ +% Operators and Overloading + +Coming soon! diff --git a/src/doc/trpl/patterns.md b/src/doc/trpl/patterns.md index 4ebf696aa5..c88e3a0f9e 100644 --- a/src/doc/trpl/patterns.md +++ b/src/doc/trpl/patterns.md @@ -1,13 +1,16 @@ % Patterns -We've made use of patterns a few times in the guide: first with `let` bindings, -then with `match` statements. Let's go on a whirlwind tour of all of the things -patterns can do! +Patterns are quite common in Rust. We use them in [variable +bindings][bindings], [match statements][match], and other places, too. Let’s go +on a whirlwind tour of all of the things patterns can do! + +[bindings]: variable-bindings.html +[match]: match.html A quick refresher: you can match against literals directly, and `_` acts as an -*any* case: +‘any’ case: -```{rust} +```rust let x = 1; match x { @@ -18,9 +21,11 @@ match x { } ``` +# Multiple patterns + You can match multiple patterns with `|`: -```{rust} +```rust let x = 1; match x { @@ -30,9 +35,11 @@ match x { } ``` +# Ranges + You can match a range of values with `...`: -```{rust} +```rust let x = 1; match x { @@ -43,10 +50,12 @@ match x { Ranges are mostly used with integers and single characters. -If you're matching multiple things, via a `|` or a `...`, you can bind +# Bindings + +If you’re matching multiple things, via a `|` or a `...`, you can bind the value to a name with `@`: -```{rust} +```rust let x = 1; match x { @@ -55,10 +64,12 @@ match x { } ``` -If you're matching on an enum which has variants, you can use `..` to +# Ignoring variants + +If you’re matching on an enum which has variants, you can use `..` to ignore the value and type in the variant: -```{rust} +```rust enum OptionalInt { Value(i32), Missing, @@ -72,9 +83,11 @@ match x { } ``` -You can introduce *match guards* with `if`: +# Guards + +You can introduce ‘match guards’ with `if`: -```{rust} +```rust enum OptionalInt { Value(i32), Missing, @@ -89,24 +102,11 @@ match x { } ``` -If you're matching on a pointer, you can use the same syntax as you declared it -with. First, `&`: - -```{rust} -let x = &5; - -match x { - &val => println!("Got a value: {}", val), -} -``` - -Here, the `val` inside the `match` has type `i32`. In other words, the left-hand -side of the pattern destructures the value. If we have `&5`, then in `&val`, `val` -would be `5`. +# ref and ref mut -If you want to get a reference, use the `ref` keyword: +If you want to get a [reference][ref], use the `ref` keyword: -```{rust} +```rust let x = 5; match x { @@ -114,11 +114,13 @@ match x { } ``` +[ref]: references-and-borrowing.html + Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` keyword _creates_ a reference, for use in the pattern. If you need a mutable reference, `ref mut` will work in the same way: -```{rust} +```rust let mut x = 5; match x { @@ -126,10 +128,12 @@ match x { } ``` -If you have a struct, you can destructure it inside of a pattern: +# Destructuring + +If you have a compound data type, like a `struct`, you can destructure it +inside of a pattern: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -142,10 +146,9 @@ match origin { } ``` -If we only care about some of the values, we don't have to give them all names: +If we only care about some of the values, we don’t have to give them all names: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -160,8 +163,7 @@ match origin { You can do this kind of match on any member, not just the first: -```{rust} -# #![allow(non_shorthand_field_patterns)] +```rust struct Point { x: i32, y: i32, @@ -174,22 +176,16 @@ match origin { } ``` -If you want to match against a slice or array, you can use `&`: +This ‘destructuring’ behavior works on any compound data type, like +[tuples][tuples] or [enums][enums]. -```{rust} -# #![feature(slice_patterns)] -fn main() { - let v = vec!["match_this", "1"]; +[tuples]: primitive-types.html#tuples +[enums]: enums.html - match &v[..] { - ["match_this", second] => println!("The second element is {}", second), - _ => {}, - } -} -``` +# Mix and Match -Whew! That's a lot of different ways to match things, and they can all be -mixed and matched, depending on what you're doing: +Whew! That’s a lot of different ways to match things, and they can all be +mixed and matched, depending on what you’re doing: ```{rust,ignore} match x { diff --git a/src/doc/trpl/pointers.md b/src/doc/trpl/pointers.md deleted file mode 100644 index 1b3f2a5b77..0000000000 --- a/src/doc/trpl/pointers.md +++ /dev/null @@ -1,699 +0,0 @@ -% Pointers - -Rust's pointers are one of its more unique and compelling features. Pointers -are also one of the more confusing topics for newcomers to Rust. They can also -be confusing for people coming from other languages that support pointers, such -as C++. This guide will help you understand this important topic. - -Be sceptical of non-reference pointers in Rust: use them for a deliberate -purpose, not just to make the compiler happy. Each pointer type comes with an -explanation about when they are appropriate to use. Default to references -unless you're in one of those specific situations. - -You may be interested in the [cheat sheet](#cheat-sheet), which gives a quick -overview of the types, names, and purpose of the various pointers. - -# An introduction - -If you aren't familiar with the concept of pointers, here's a short -introduction. Pointers are a very fundamental concept in systems programming -languages, so it's important to understand them. - -## Pointer Basics - -When you create a new variable binding, you're giving a name to a value that's -stored at a particular location on the stack. (If you're not familiar with the -*heap* vs. *stack*, please check out [this Stack Overflow -question](http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap), -as the rest of this guide assumes you know the difference.) Like this: - -```{rust} -let x = 5; -let y = 8; -``` - -| location | value | -|----------|-------| -| 0xd3e030 | 5 | -| 0xd3e028 | 8 | - -We're making up memory locations here, they're just sample values. Anyway, the -point is that `x`, the name we're using for our variable, corresponds to the -memory location `0xd3e030`, and the value at that location is `5`. When we -refer to `x`, we get the corresponding value. Hence, `x` is `5`. - -Let's introduce a pointer. In some languages, there is just one type of -'pointer,' but in Rust, we have many types. In this case, we'll use a Rust -*reference*, which is the simplest kind of pointer. - -```{rust} -let x = 5; -let y = 8; -let z = &y; -``` - -|location | value | -|-------- |----------| -|0xd3e030 | 5 | -|0xd3e028 | 8 | -|0xd3e020 | 0xd3e028 | - -See the difference? Rather than contain a value, the value of a pointer is a -location in memory. In this case, the location of `y`. `x` and `y` have the -type `i32`, but `z` has the type `&i32`. We can print this location using the -`{:p}` format string: - -```{rust} -let x = 5; -let y = 8; -let z = &y; - -println!("{:p}", z); -``` - -This would print `0xd3e028`, with our fictional memory addresses. - -Because `i32` and `&i32` are different types, we can't, for example, add them -together: - -```{rust,ignore} -let x = 5; -let y = 8; -let z = &y; - -println!("{}", x + z); -``` - -This gives us an error: - -```text -hello.rs:6:24: 6:25 error: mismatched types: expected `_`, found `&_` (expected integral variable, found &-ptr) -hello.rs:6 println!("{}", x + z); - ^ -``` - -We can *dereference* the pointer by using the `*` operator. Dereferencing a -pointer means accessing the value at the location stored in the pointer. This -will work: - -```{rust} -let x = 5; -let y = 8; -let z = &y; - -println!("{}", x + *z); -``` - -It prints `13`. - -That's it! That's all pointers are: they point to some memory location. Not -much else to them. Now that we've discussed the *what* of pointers, let's -talk about the *why*. - -## Pointer uses - -Rust's pointers are quite useful, but in different ways than in other systems -languages. We'll talk about best practices for Rust pointers later in -the guide, but here are some ways that pointers are useful in other languages: - -In C, strings are a pointer to a list of `char`s, ending with a null byte. -The only way to use strings is to get quite familiar with pointers. - -Pointers are useful to point to memory locations that are not on the stack. For -example, our example used two stack variables, so we were able to give them -names. But if we allocated some heap memory, we wouldn't have that name -available. In C, `malloc` is used to allocate heap memory, and it returns a -pointer. - -As a more general variant of the previous two points, any time you have a -structure that can change in size, you need a pointer. You can't tell at -compile time how much memory to allocate, so you've gotta use a pointer to -point at the memory where it will be allocated, and deal with it at run time. - -Pointers are useful in languages that are pass-by-value, rather than -pass-by-reference. Basically, languages can make two choices (this is made -up syntax, it's not Rust): - -```text -func foo(x) { - x = 5 -} - -func main() { - i = 1 - foo(i) - // what is the value of i here? -} -``` - -In languages that are pass-by-value, `foo` will get a copy of `i`, and so -the original version of `i` is not modified. At the comment, `i` will still be -`1`. In a language that is pass-by-reference, `foo` will get a reference to `i`, -and therefore, can change its value. At the comment, `i` will be `5`. - -So what do pointers have to do with this? Well, since pointers point to a -location in memory... - -```text -func foo(&i32 x) { - *x = 5 -} - -func main() { - i = 1 - foo(&i) - // what is the value of i here? -} -``` - -Even in a language which is pass by value, `i` will be `5` at the comment. You -see, because the argument `x` is a pointer, we do send a copy over to `foo`, -but because it points at a memory location, which we then assign to, the -original value is still changed. This pattern is called -*pass-reference-by-value*. Tricky! - -## Common pointer problems - -We've talked about pointers, and we've sung their praises. So what's the -downside? Well, Rust attempts to mitigate each of these kinds of problems, -but here are problems with pointers in other languages: - -Uninitialized pointers can cause a problem. For example, what does this program -do? - -```{ignore} -&int x; -*x = 5; // whoops! -``` - -Who knows? We just declare a pointer, but don't point it at anything, and then -set the memory location that it points at to be `5`. But which location? Nobody -knows. This might be harmless, and it might be catastrophic. - -When you combine pointers and functions, it's easy to accidentally invalidate -the memory the pointer is pointing to. For example: - -```text -func make_pointer(): &int { - x = 5; - - return &x; -} - -func main() { - &int i = make_pointer(); - *i = 5; // uh oh! -} -``` - -`x` is local to the `make_pointer` function, and therefore, is invalid as soon -as `make_pointer` returns. But we return a pointer to its memory location, and -so back in `main`, we try to use that pointer, and it's a very similar -situation to our first one. Setting invalid memory locations is bad. - -As one last example of a big problem with pointers, *aliasing* can be an -issue. Two pointers are said to alias when they point at the same location -in memory. Like this: - -```text -func mutate(&int i, int j) { - *i = j; -} - -func main() { - x = 5; - y = &x; - z = &x; //y and z are aliased - - - run_in_new_thread(mutate, y, 1); - run_in_new_thread(mutate, z, 100); - - // what is the value of x here? -} -``` - -In this made-up example, `run_in_new_thread` spins up a new thread, and calls -the given function name with its arguments. Since we have two threads, and -they're both operating on aliases to `x`, we can't tell which one finishes -first, and therefore, the value of `x` is actually non-deterministic. Worse, -what if one of them had invalidated the memory location they pointed to? We'd -have the same problem as before, where we'd be setting an invalid location. - -## Conclusion - -That's a basic overview of pointers as a general concept. As we alluded to -before, Rust has different kinds of pointers, rather than just one, and -mitigates all of the problems that we talked about, too. This does mean that -Rust pointers are slightly more complicated than in other languages, but -it's worth it to not have the problems that simple pointers have. - -# References - -The most basic type of pointer that Rust has is called a *reference*. Rust -references look like this: - -```{rust} -let x = 5; -let y = &x; - -println!("{}", *y); -println!("{:p}", y); -println!("{}", y); -``` - -We'd say "`y` is a reference to `x`." The first `println!` prints out the -value of `y`'s referent by using the dereference operator, `*`. The second -one prints out the memory location that `y` points to, by using the pointer -format string. The third `println!` *also* prints out the value of `y`'s -referent, because `println!` will automatically dereference it for us. - -Here's a function that takes a reference: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -You can also use `&` as an operator to create a reference, so we can -call this function in two different ways: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } - -fn main() { - - let x = 5; - let y = &x; - - println!("{}", succ(y)); - println!("{}", succ(&x)); -} -``` - -Both of these `println!`s will print out `6`. - -Of course, if this were real code, we wouldn't bother with the reference, and -just write: - -```{rust} -fn succ(x: i32) -> i32 { x + 1 } -``` - -References are immutable by default: - -```{rust,ignore} -let x = 5; -let y = &x; - -*y = 5; // error: cannot assign to immutable borrowed content `*y` -``` - -They can be made mutable with `mut`, but only if its referent is also mutable. -This works: - -```{rust} -let mut x = 5; -let y = &mut x; -``` - -This does not: - -```{rust,ignore} -let x = 5; -let y = &mut x; // error: cannot borrow immutable local variable `x` as mutable -``` - -Immutable pointers are allowed to alias: - -```{rust} -let x = 5; -let y = &x; -let z = &x; -``` - -Mutable ones, however, are not: - -```{rust,ignore} -let mut x = 5; -let y = &mut x; -let z = &mut x; // error: cannot borrow `x` as mutable more than once at a time -``` - -Despite their complete safety, a reference's representation at runtime is the -same as that of an ordinary pointer in a C program. They introduce zero -overhead. The compiler does all safety checks at compile time. The theory that -allows for this was originally called *region pointers*. Region pointers -evolved into what we know today as *lifetimes*. - -Here's the simple explanation: would you expect this code to compile? - -```{rust,ignore} -fn main() { - println!("{}", x); - let x = 5; -} -``` - -Probably not. That's because you know that the name `x` is valid from where -it's declared to when it goes out of scope. In this case, that's the end of -the `main` function. So you know this code will cause an error. We call this -duration a *lifetime*. Let's try a more complex example: - -```{rust} -fn main() { - let mut x = 5; - - if x < 10 { - let y = &x; - - println!("Oh no: {}", y); - return; - } - - x -= 1; - - println!("Oh no: {}", x); -} -``` - -Here, we're borrowing a pointer to `x` inside of the `if`. The compiler, however, -is able to determine that that pointer will go out of scope without `x` being -mutated, and therefore, lets us pass. This wouldn't work: - -```{rust,ignore} -fn main() { - let mut x = 5; - - if x < 10 { - let y = &x; - - x -= 1; - - println!("Oh no: {}", y); - return; - } - - x -= 1; - - println!("Oh no: {}", x); -} -``` - -It gives this error: - -```text -test.rs:7:9: 7:15 error: cannot assign to `x` because it is borrowed -test.rs:7 x -= 1; - ^~~~~~ -test.rs:5:18: 5:19 note: borrow of `x` occurs here -test.rs:5 let y = &x; - ^ -``` - -As you might guess, this kind of analysis is complex for a human, and therefore -hard for a computer, too! There is an entire [guide devoted to references, ownership, -and lifetimes](ownership.html) that goes into this topic in -great detail, so if you want the full details, check that out. - -## Best practices - -In general, prefer stack allocation over heap allocation. Using references to -stack allocated information is preferred whenever possible. Therefore, -references are the default pointer type you should use, unless you have a -specific reason to use a different type. The other types of pointers cover when -they're appropriate to use in their own best practices sections. - -Use references when you want to use a pointer, but do not want to take ownership. -References just borrow ownership, which is more polite if you don't need the -ownership. In other words, prefer: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -to - -```{rust} -fn succ(x: Box) -> i32 { *x + 1 } -``` - -As a corollary to that rule, references allow you to accept a wide variety of -other pointers, and so are useful so that you don't have to write a number -of variants per pointer. In other words, prefer: - -```{rust} -fn succ(x: &i32) -> i32 { *x + 1 } -``` - -to - -```{rust} -use std::rc::Rc; - -fn box_succ(x: Box) -> i32 { *x + 1 } - -fn rc_succ(x: Rc) -> i32 { *x + 1 } -``` - -Note that the caller of your function will have to modify their calls slightly: - -```{rust} -use std::rc::Rc; - -fn succ(x: &i32) -> i32 { *x + 1 } - -let ref_x = &5; -let box_x = Box::new(5); -let rc_x = Rc::new(5); - -succ(ref_x); -succ(&*box_x); -succ(&*rc_x); -``` - -The initial `*` dereferences the pointer, and then `&` takes a reference to -those contents. - -# Boxes - -`Box` is Rust's *boxed pointer* type. Boxes provide the simplest form of -heap allocation in Rust. Creating a box looks like this: - -```{rust} -let x = Box::new(5); -``` - -Boxes are heap allocated and they are deallocated automatically by Rust when -they go out of scope: - -```{rust} -{ - let x = Box::new(5); - - // stuff happens - -} // x is destructed and its memory is free'd here -``` - -However, boxes do _not_ use reference counting or garbage collection. Boxes are -what's called an *affine type*. This means that the Rust compiler, at compile -time, determines when the box comes into and goes out of scope, and inserts the -appropriate calls there. - -You don't need to fully grok the theory of affine types to grok boxes, though. -As a rough approximation, you can treat this Rust code: - -```{rust} -{ - let x = Box::new(5); - - // stuff happens -} -``` - -As being similar to this C code: - -```c -{ - int *x; - x = (int *)malloc(sizeof(int)); - *x = 5; - - // stuff happens - - free(x); -} -``` - -Of course, this is a 10,000 foot view. It leaves out destructors, for example. -But the general idea is correct: you get the semantics of `malloc`/`free`, but -with some improvements: - -1. It's impossible to allocate the incorrect amount of memory, because Rust - figures it out from the types. -2. You cannot forget to `free` memory you've allocated, because Rust does it - for you. -3. Rust ensures that this `free` happens at the right time, when it is truly - not used. Use-after-free is not possible. -4. Rust enforces that no other writeable pointers alias to this heap memory, - which means writing to an invalid pointer is not possible. - -See the section on references or the [ownership guide](ownership.html) -for more detail on how lifetimes work. - -Using boxes and references together is very common. For example: - -```{rust} -fn add_one(x: &i32) -> i32 { - *x + 1 -} - -fn main() { - let x = Box::new(5); - - println!("{}", add_one(&*x)); -} -``` - -In this case, Rust knows that `x` is being *borrowed* by the `add_one()` -function, and since it's only reading the value, allows it. - -We can borrow `x` as read-only multiple times, even simultaneously: - -```{rust} -fn add(x: &i32, y: &i32) -> i32 { - *x + *y -} - -fn main() { - let x = Box::new(5); - - println!("{}", add(&*x, &*x)); - println!("{}", add(&*x, &*x)); -} -``` - -We can mutably borrow `x` multiple times, but only if x itself is mutable, and -it may not be *simultaneously* borrowed: - -```{rust,ignore} -fn increment(x: &mut i32) { - *x += 1; -} - -fn main() { - // If variable x is not "mut", this will not compile - let mut x = Box::new(5); - - increment(&mut x); - increment(&mut x); - println!("{}", x); -} -``` - -Notice the signature of `increment()` requests a mutable reference. - -## Best practices - -Boxes are most appropriate to use when defining recursive data structures. - -### Recursive data structures - -Sometimes, you need a recursive data structure. The simplest is known as a -*cons list*: - - -```{rust} -#[derive(Debug)] -enum List { - Cons(T, Box>), - Nil, -} - -fn main() { - let list: List = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Cons(3, Box::new(List::Nil)))))); - println!("{:?}", list); -} -``` - -This prints: - -```text -Cons(1, Box(Cons(2, Box(Cons(3, Box(Nil)))))) -``` - -The reference to another `List` inside of the `Cons` enum variant must be a box, -because we don't know the length of the list. Because we don't know the length, -we don't know the size, and therefore, we need to heap allocate our list. - -Working with recursive or other unknown-sized data structures is the primary -use-case for boxes. - -# Rc and Arc - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Raw Pointers - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Creating your own Pointers - -This part is coming soon. - -## Best practices - -This part is coming soon. - -# Patterns and `ref` - -When you're trying to match something that's stored in a pointer, there may be -a situation where matching directly isn't the best option available. Let's see -how to properly handle this: - -```{rust,ignore} -fn possibly_print(x: &Option) { - match *x { - // BAD: cannot move out of a `&` - Some(s) => println!("{}", s) - - // GOOD: instead take a reference into the memory of the `Option` - Some(ref s) => println!("{}", *s), - None => {} - } -} -``` - -The `ref s` here means that `s` will be of type `&String`, rather than type -`String`. - -This is important when the type you're trying to get access to has a destructor -and you don't want to move it, you just want a reference to it. - -# Cheat Sheet - -Here's a quick rundown of Rust's pointer types: - -| Type | Name | Summary | -|--------------|---------------------|---------------------------------------------------------------------| -| `&T` | Reference | Allows one or more references to read `T` | -| `&mut T` | Mutable Reference | Allows a single reference to read and write `T` | -| `Box` | Box | Heap allocated `T` with a single owner that may read and write `T`. | -| `Rc` | "arr cee" pointer | Heap allocated `T` with many readers | -| `Arc` | Arc pointer | Same as above, but safe sharing across threads | -| `*const T` | Raw pointer | Unsafe read access to `T` | -| `*mut T` | Mutable raw pointer | Unsafe read and write access to `T` | - -# Related resources - -* [API documentation for Box](../std/boxed/index.html) -* [Ownership guide](ownership.html) -* [Cyclone paper on regions](http://www.cs.umd.edu/projects/cyclone/papers/cyclone-regions.pdf), which inspired Rust's lifetime system diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md new file mode 100644 index 0000000000..fcbe2b2f8b --- /dev/null +++ b/src/doc/trpl/primitive-types.md @@ -0,0 +1,268 @@ +% Primitive Types + +The Rust language has a number of types that are considered ‘primitive’. This +means that they’re built-in to the language. Rust is structured in such a way +that the standard library also provides a number of useful types built on top +of these ones, as well, but these are the most primitive. + +# Booleans + +Rust has a built in boolean type, named `bool`. It has two values, `true` and `false`: + +```rust +let x = true; + +let y: bool = false; +``` + +A common use of booleans is in [`if` statements][if]. + +[if]: if.html + +You can find more documentation for `bool`s [in the standard library +documentation][bool]. + +[bool]: ../std/primitive.bool.html + +# `char` + +The `char` type represents a single Unicode scalar value. You can create `char`s +with a single tick: (`'`) + +```rust +let x = 'x'; +let two_hearts = '💕'; +``` + +Unlike some other languages, this means that Rust’s `char` is not a single byte, +but four. + +You can find more documentation for `char`s [in the standard library +documentation][char]. + +[char]: ../std/primitive.char.html + +# Numeric types + +Rust has a variety of numeric types in a few categories: signed and unsigned, +fixed and variable, floating-point and integer. + +These types consist of two parts: the category, and the size. For example, +`u16` is an unsigned type with sixteen bits of size. More bits lets you have +bigger numbers. + +If a number literal has nothing to cause its type to be inferred, it defaults: + +```rust +let x = 42; // x has type i32 + +let y = 1.0; // y has type f64 +``` + +Here’s a list of the different numeric types, with links to their documentation +in the standard library: + +* [i16](../std/primitive.i16.html) +* [i32](../std/primitive.i32.html) +* [i64](../std/primitive.i64.html) +* [i8](../std/primitive.i8.html) +* [u16](../std/primitive.u16.html) +* [u32](../std/primitive.u32.html) +* [u64](../std/primitive.u64.html) +* [u8](../std/primitive.u8.html) +* [isize](../std/primitive.isize.html) +* [usize](../std/primitive.usize.html) +* [f32](../std/primitive.f32.html) +* [f64](../std/primitive.f64.html) + +Let’s go over them by category: + +## Signed and Unsigned + +Integer types come in two varieties: signed and unsigned. To understand the +difference, let’s consider a number with four bits of size. A signed, four-bit +number would let you store numbers from `-8` to `+7`. Signed numbers use +‘two’s compliment representation’. An unsigned four bit number, since it does +not need to store negatives, can store values from `0` to `+15`. + +Unsigned types use a `u` for their category, and signed types use `i`. The `i` +is for ‘integer’. So `u8` is an eight-bit unsigned number, and `i8` is an +eight-bit signed number. + +## Fixed size types + +Fixed size types have a specific number of bits in their representation. Valid +bit sizes are `8`, `16`, `32`, and `64`. So, `u32` is an unsigned, 32-bit integer, +and `i64` is a signed, 64-bit integer. + +## Variable sized types + +Rust also provides types whose size depends on the size of a pointer of the +underlying machine. These types have ‘size’ as the category, and come in signed +and unsigned varieties. This makes for two types: `isize` and `usize`. + +## Floating-point types + +Rust also two floating point types: `f32` and `f64`. These correspond to +IEEE-754 single and double precision numbers. + +# Arrays + +Like many programming languages, Rust has list types to represent a sequence of +things. The most basic is the *array*, a fixed-size list of elements of the +same type. By default, arrays are immutable. + +```rust +let a = [1, 2, 3]; // a: [i32; 3] +let mut m = [1, 2, 3]; // m: [i32; 3] +``` + +Arrays have type `[T; N]`. We’ll talk about this `T` notation [in the generics +section][generics]. The `N` is a compile-time constant, for the length of the +array. + +There’s a shorthand for initializing each element of an array to the same +value. In this example, each element of `a` will be initialized to `0`: + +```rust +let a = [0; 20]; // a: [i32; 20] +``` + +You can get the number of elements in an array `a` with `a.len()`: + +```rust +let a = [1, 2, 3]; + +println!("a has {} elements", a.len()); +``` + +You can access a particular element of an array with *subscript notation*: + +```rust +let names = ["Graydon", "Brian", "Niko"]; // names: [&str; 3] + +println!("The second name is: {}", names[1]); +``` + +Subscripts start at zero, like in most programming languages, so the first name +is `names[0]` and the second name is `names[1]`. The above example prints +`The second name is: Brian`. If you try to use a subscript that is not in the +array, you will get an error: array access is bounds-checked at run-time. Such +errant access is the source of many bugs in other systems programming +languages. + +You can find more documentation for `array`s [in the standard library +documentation][array]. + +[array]: ../std/primitive.array.html + +# Slices + +A ‘slice’ is a reference to (or “view” into) another data structure. They are +useful for allowing safe, efficient access to a portion of an array without +copying. For example, you might want to reference just one line of a file read +into memory. By nature, a slice is not created directly, but from an existing +variable. Slices have a length, can be mutable or not, and in many ways behave +like arrays: + +```rust +let a = [0, 1, 2, 3, 4]; +let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3 +``` + +Slices have type `&[T]`. We’ll talk about that `T` when we cover +[generics][generics]. + +[generics]: generics.html + +You can find more documentation for `slices`s [in the standard library +documentation][slice]. + +[slice]: ../std/primitive.slice.html + +# `str` + +Rust’s `str` type is the most primitive string type. As an [unsized type][dst], +it’s not very useful by itself, but becomes useful when placed behind a reference, +like [`&str`][strings]. As such, we’ll just leave it at that. + +[dst]: unsized-types.html +[strings]: strings.html + +You can find more documentation for `str` [in the standard library +documentation][str]. + +[str]: ../std/primitive.str.html + +# Tuples + +A tuple is an ordered list of fixed size. Like this: + +```rust +let x = (1, "hello"); +``` + +The parentheses and commas form this two-length tuple. Here’s the same code, but +with the type annotated: + +```rust +let x: (i32, &str) = (1, "hello"); +``` + +As you can see, the type of a tuple looks just like the tuple, but with each +position having a type name rather than the value. Careful readers will also +note that tuples are heterogeneous: we have an `i32` and a `&str` in this tuple. +In systems programming languages, strings are a bit more complex than in other +languages. For now, just read `&str` as a *string slice*, and we’ll learn more +soon. + +You can access the fields in a tuple through a *destructuring let*. Here’s +an example: + +```rust +let (x, y, z) = (1, 2, 3); + +println!("x is {}", x); +``` + +Remember [before][let] when I said the left-hand side of a `let` statement was more +powerful than just assigning a binding? Here we are. We can put a pattern on +the left-hand side of the `let`, and if it matches up to the right-hand side, +we can assign multiple bindings at once. In this case, `let` "destructures," +or "breaks up," the tuple, and assigns the bits to three bindings. + +[let]: variable-bindings.html + +This pattern is very powerful, and we’ll see it repeated more later. + +There are also a few things you can do with a tuple as a whole, without +destructuring. You can assign one tuple into another, if they have the same +contained types and [arity]. Tuples have the same arity when they have the same +length. + +[arity]: glossary.html#arity + +```rust +let mut x = (1, 2); // x: (i32, i32) +let y = (2, 3); // y: (i32, i32) + +x = y; +``` + +You can find more documentation for tuples [in the standard library +documentation][tuple]. + +[tuple]: ../std/primitive.tuple.html + +# Functions + +Functions also have a type! They look like this: + +``` +fn foo(x: i32) -> i32 { x } + +let x: fn(i32) -> i32 = foo; +``` + +In this case, `x` is a ‘function pointer’ to a function that takes an `i32` and +returns an `i32`. diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md new file mode 100644 index 0000000000..6acb326958 --- /dev/null +++ b/src/doc/trpl/references-and-borrowing.md @@ -0,0 +1,3 @@ +% References and Borrowing + +Coming Soon! diff --git a/src/doc/trpl/slice-patterns.md b/src/doc/trpl/slice-patterns.md new file mode 100644 index 0000000000..4599333a77 --- /dev/null +++ b/src/doc/trpl/slice-patterns.md @@ -0,0 +1,18 @@ +% Slice patterns + +If you want to match against a slice or array, you can use `&` with the +`slice_patterns` feature: + +```rust +#![feature(slice_patterns)] + +fn main() { + let v = vec!["match_this", "1"]; + + match &v[..] { + ["match_this", second] => println!("The second element is {}", second), + _ => {}, + } +} +``` + diff --git a/src/doc/trpl/static.md b/src/doc/trpl/static.md new file mode 100644 index 0000000000..b29c4952c9 --- /dev/null +++ b/src/doc/trpl/static.md @@ -0,0 +1,3 @@ +% `static` + +Coming soon! diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md new file mode 100644 index 0000000000..83d5a15bc2 --- /dev/null +++ b/src/doc/trpl/structs.md @@ -0,0 +1,89 @@ +% Structs + +Structs are a way of creating more complex datatypes. For example, if we were +doing calculations involving coordinates in 2D space, we would need both an `x` +and a `y` value: + +```rust +let origin_x = 0; +let origin_y = 0; +``` + +A struct lets us combine these two into a single, unified datatype: + +```rust +struct Point { + x: i32, + y: i32, +} + +fn main() { + let origin = Point { x: 0, y: 0 }; // origin: Point + + println!("The origin is at ({}, {})", origin.x, origin.y); +} +``` + +There’s a lot going on here, so let’s break it down. We declare a struct with +the `struct` keyword, and then with a name. By convention, structs begin with a +capital letter and are also camel cased: `PointInSpace`, not `Point_In_Space`. + +We can create an instance of our struct via `let`, as usual, but we use a `key: +value` style syntax to set each field. The order doesn't need to be the same as +in the original declaration. + +Finally, because fields have names, we can access the field through dot +notation: `origin.x`. + +The values in structs are immutable by default, like other bindings in Rust. +Use `mut` to make them mutable: + +```rust +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut point = Point { x: 0, y: 0 }; + + point.x = 5; + + println!("The point is at ({}, {})", point.x, point.y); +} +``` + +This will print `The point is at (5, 0)`. + +Rust does not support field mutability at the language level, so you cannot +write something like this: + +```rust,ignore +struct Point { + mut x: i32, + y: i32, +} +``` + +Mutability is a property of the binding, not of the structure itself. If you’re +used to field-level mutability, this may seem strange at first, but it +significantly simplifies things. It even lets you make things mutable for a short +time only: + + +```rust,ignore +struct Point { + x: i32, + y: i32, +} + +fn main() { + let mut point = Point { x: 0, y: 0 }; + + point.x = 5; + + let point = point; // this new binding can’t change now + + point.y = 6; // this causes an error +} +``` diff --git a/src/doc/trpl/syntax-and-semantics.md b/src/doc/trpl/syntax-and-semantics.md new file mode 100644 index 0000000000..cce985c9e4 --- /dev/null +++ b/src/doc/trpl/syntax-and-semantics.md @@ -0,0 +1,10 @@ +% Syntax and Semantics + +This section breaks Rust down into small chunks, one for each concept. + +If you’d like to learn Rust from the bottom up, reading this in order is a +great way to do that. + +These sections also form a reference for each concept, so if you’re reading +another tutorial and find something confusing, you can find it explained +somewhere in here. diff --git a/src/doc/trpl/testing.md b/src/doc/trpl/testing.md index fddb4c1903..8cf126cad9 100644 --- a/src/doc/trpl/testing.md +++ b/src/doc/trpl/testing.md @@ -382,7 +382,7 @@ pub fn add_two(a: i32) -> i32 { } #[cfg(test)] -mod tests { +mod test { use super::*; #[test] diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md new file mode 100644 index 0000000000..cc0941bc02 --- /dev/null +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -0,0 +1,3 @@ +% The Stack and the Heap + +Coming Soon diff --git a/src/doc/trpl/tracing-macros.md b/src/doc/trpl/tracing-macros.md deleted file mode 100644 index 6226ea9f3e..0000000000 --- a/src/doc/trpl/tracing-macros.md +++ /dev/null @@ -1,91 +0,0 @@ -% Tracing Macros - -The `trace_macros` feature allows you to use a special feature: tracing macro -invocations. - -In the advanced macros chapter, we defined a `bct` macro: - -```rust -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} -``` - -This is pretty complex! we can see the output - -```rust,ignore -#![feature(trace_macros)] - -macro_rules! bct { - // cmd 0: d ... => ... - (0, $($ps:tt),* ; $_d:tt) - => (bct!($($ps),*, 0 ; )); - (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*) - => (bct!($($ps),*, 0 ; $($ds),*)); - - // cmd 1p: 1 ... => 1 ... p - (1, $p:tt, $($ps:tt),* ; 1) - => (bct!($($ps),*, 1, $p ; 1, $p)); - (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p)); - - // cmd 1p: 0 ... => 0 ... - (1, $p:tt, $($ps:tt),* ; $($ds:tt),*) - => (bct!($($ps),*, 1, $p ; $($ds),*)); - - // halt on empty data string - ( $($ps:tt),* ; ) - => (()); -} - -fn main() { - trace_macros!(true); - - bct!(0, 0, 1, 1, 1 ; 1, 0, 1); -} -``` - -This will print out a wall of text: - -```text -bct! { 0 , 0 , 1 , 1 , 1 ; 1 , 0 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 } -bct! { 1 , 1 , 1 , 0 , 0 ; 1 } -bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 1 , 0 } -bct! { 1 , 1 , 1 , 0 , 0 ; 1 , 0 } -bct! { 1 , 0 , 0 , 1 , 1 ; 1 , 0 , 1 } -bct! { 0 , 1 , 1 , 1 , 0 ; 1 , 0 , 1 , 0 } -bct! { 1 , 1 , 1 , 0 , 0 ; 0 , 1 , 0 } -bct! { 1 , 0 , 0 , 1 , 1 ; 0 , 1 , 0 } -bct! { 0 , 1 , 1 , 1 , 0 ; 0 , 1 , 0 } -``` - -And eventually, error: - -```text -18:45 error: recursion limit reached while expanding the macro `bct` - => (bct!($($ps),*, 1, $p ; $($ds),*)); - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -``` - -The `trace_macros!` call is what produces this output, showing how we match -each time. diff --git a/src/doc/trpl/static-and-dynamic-dispatch.md b/src/doc/trpl/trait-objects.md similarity index 99% rename from src/doc/trpl/static-and-dynamic-dispatch.md rename to src/doc/trpl/trait-objects.md index a779481415..d008d30597 100644 --- a/src/doc/trpl/static-and-dynamic-dispatch.md +++ b/src/doc/trpl/trait-objects.md @@ -1,4 +1,4 @@ -% Static and Dynamic Dispatch +% Trait Objects When code involves polymorphism, there needs to be a mechanism to determine which specific version is actually run. This is called 'dispatch.' There are diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index 341c90a708..d7bf3ef5f4 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -229,8 +229,6 @@ everything is fine: ```{rust} # #![feature(core)] -use shapes::HasArea; - mod shapes { use std::f64::consts; @@ -251,6 +249,7 @@ mod shapes { } } +use shapes::HasArea; fn main() { let c = shapes::Circle { @@ -274,8 +273,8 @@ not, because both the trait and the type aren't in our crate. One last thing about traits: generic functions with a trait bound use *monomorphization* (*mono*: one, *morph*: form), so they are statically -dispatched. What's that mean? Check out the chapter on [static and dynamic -dispatch](static-and-dynamic-dispatch.html) for more. +dispatched. What's that mean? Check out the chapter on [trait +objects](trait-objects.html) for more. ## Multiple trait bounds @@ -390,81 +389,6 @@ This shows off the additional feature of `where` clauses: they allow bounds where the left-hand side is an arbitrary type (`i32` in this case), not just a plain type parameter (like `T`). -## Our `inverse` Example - -Back in [Generics](generics.html), we were trying to write code like this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -If we try to compile it, we get this error: - -```text -error: binary operation `==` cannot be applied to type `T` -``` - -This is because `T` is too generic: we don't know if a random `T` can be -compared. For that, we can use trait bounds. It doesn't quite work, but try -this: - -```{rust,ignore} -fn inverse(x: T) -> Result { - if x == 0.0 { return Err("x cannot be zero!".to_string()); } - - Ok(1.0 / x) -} -``` - -You should get this error: - -```text -error: mismatched types: - expected `T`, - found `_` -(expected type parameter, - found floating-point variable) -``` - -So this won't work. While our `T` is `PartialEq`, we expected to have another `T`, -but instead, we found a floating-point variable. We need a different bound. `Float` -to the rescue: - -``` -# #![feature(std_misc)] -use std::num::Float; - -fn inverse(x: T) -> Result { - if x == Float::zero() { return Err("x cannot be zero!".to_string()) } - - let one: T = Float::one(); - Ok(one / x) -} -``` - -We've had to replace our generic `0.0` and `1.0` with the appropriate methods -from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function -works just fine: - -``` -# #![feature(std_misc)] -# use std::num::Float; -# fn inverse(x: T) -> Result { -# if x == Float::zero() { return Err("x cannot be zero!".to_string()) } -# let one: T = Float::one(); -# Ok(one / x) -# } -println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32)); -println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64)); - -println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32)); -println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64)); -``` - ## Default methods There's one last feature of traits we should cover: default methods. It's diff --git a/src/doc/trpl/tuple-structs.md b/src/doc/trpl/tuple-structs.md new file mode 100644 index 0000000000..8fba658fba --- /dev/null +++ b/src/doc/trpl/tuple-structs.md @@ -0,0 +1,56 @@ +% Tuple Structs + +Rust has another data type that's like a hybrid between a tuple and a struct, +called a *tuple struct*. Tuple structs do have a name, but their fields don't: + +```{rust} +struct Color(i32, i32, i32); +struct Point(i32, i32, i32); +``` + +These two will not be equal, even if they have the same values: + +```{rust} +# struct Color(i32, i32, i32); +# struct Point(i32, i32, i32); +let black = Color(0, 0, 0); +let origin = Point(0, 0, 0); +``` + +It is almost always better to use a struct than a tuple struct. We would write +`Color` and `Point` like this instead: + +```{rust} +struct Color { + red: i32, + blue: i32, + green: i32, +} + +struct Point { + x: i32, + y: i32, + z: i32, +} +``` + +Now, we have actual names, rather than positions. Good names are important, +and with a struct, we have actual names. + +There _is_ one case when a tuple struct is very useful, though, and that's a +tuple struct with only one element. We call this the *newtype* pattern, because +it allows you to create a new type, distinct from that of its contained value +and expressing its own semantic meaning: + +```{rust} +struct Inches(i32); + +let length = Inches(10); + +let Inches(integer_length) = length; +println!("length is {} inches", integer_length); +``` + +As you can see here, you can extract the inner integer type through a +destructuring `let`, as we discussed previously in 'tuples.' In this case, the +`let Inches(integer_length)` assigns `10` to `integer_length`. diff --git a/src/doc/trpl/type-aliases.md b/src/doc/trpl/type-aliases.md new file mode 100644 index 0000000000..fffa0ae138 --- /dev/null +++ b/src/doc/trpl/type-aliases.md @@ -0,0 +1,3 @@ +% `type` Aliases + +Coming soon diff --git a/src/doc/trpl/ufcs.md b/src/doc/trpl/ufcs.md new file mode 100644 index 0000000000..6b9a417c43 --- /dev/null +++ b/src/doc/trpl/ufcs.md @@ -0,0 +1,3 @@ +% Universal Function Call Syntax + +Coming soon diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe-code.md similarity index 99% rename from src/doc/trpl/unsafe.md rename to src/doc/trpl/unsafe-code.md index 3ca3cfd058..b641f2b104 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe-code.md @@ -1,4 +1,4 @@ -% Unsafe and Low-Level Code +% Unsafe Code # Introduction diff --git a/src/doc/trpl/unsized-types.md b/src/doc/trpl/unsized-types.md new file mode 100644 index 0000000000..f307f23f01 --- /dev/null +++ b/src/doc/trpl/unsized-types.md @@ -0,0 +1,3 @@ +% Unsized Types + +Coming Soon! diff --git a/src/doc/trpl/unstable.md b/src/doc/trpl/unstable.md deleted file mode 100644 index e8e02cc9d0..0000000000 --- a/src/doc/trpl/unstable.md +++ /dev/null @@ -1 +0,0 @@ -% Unstable Rust diff --git a/src/doc/trpl/variable-bindings.md b/src/doc/trpl/variable-bindings.md index 88babd8659..d971e557a9 100644 --- a/src/doc/trpl/variable-bindings.md +++ b/src/doc/trpl/variable-bindings.md @@ -1,44 +1,48 @@ % Variable Bindings -The first thing we'll learn about are *variable bindings*. They look like this: +Vitually every non-’Hello World’ Rust program uses *variable bindings*. They +look like this: -```{rust} +```rust fn main() { let x = 5; } ``` -Putting `fn main() {` in each example is a bit tedious, so we'll leave that out -in the future. If you're following along, make sure to edit your `main()` -function, rather than leaving it off. Otherwise, you'll get an error. +Putting `fn main() {` in each example is a bit tedious, so we’ll leave that out +in the future. If you’re following along, make sure to edit your `main()` +function, rather than leaving it off. Otherwise, you’ll get an error. -In many languages, this is called a *variable*. But Rust's variable bindings -have a few tricks up their sleeves. Rust has a very powerful feature called -*pattern matching* that we'll get into detail with later, but the left -hand side of a `let` expression is a full pattern, not just a variable name. -This means we can do things like: +In many languages, this is called a *variable*, but Rust’s variable bindings +have a few tricks up their sleeves. For example the left-hand side of a `let` +expression is a ‘[pattern][pattern]’, not just a variable name. This means we +can do things like: -```{rust} +```rust let (x, y) = (1, 2); ``` After this expression is evaluated, `x` will be one, and `y` will be two. -Patterns are really powerful, but this is about all we can do with them so far. -So let's just keep this in the back of our minds as we go forward. +Patterns are really powerful, and have [their own section][pattern] in the +book. We don’t need those features for now, so we’ll just keep this in the back +of our minds as we go forward. + +[pattern]: patterns.html Rust is a statically typed language, which means that we specify our types up -front. So why does our first example compile? Well, Rust has this thing called -*type inference*. If it can figure out what the type of something is, Rust -doesn't require you to actually type it out. +front, and they’re checked at compile time. So why does our first example +compile? Well, Rust has this thing called ‘type inference’. If it can figure +out what the type of something is, Rust doesn’t require you to actually type it +out. We can add the type if we want to, though. Types come after a colon (`:`): -```{rust} +```rust let x: i32 = 5; ``` -If I asked you to read this out loud to the rest of the class, you'd say "`x` -is a binding with the type `i32` and the value `five`." +If I asked you to read this out loud to the rest of the class, you’d say “`x` +is a binding with the type `i32` and the value `five`.” In this case we chose to represent `x` as a 32-bit signed integer. Rust has many different primitive integer types. They begin with `i` for signed integers @@ -48,19 +52,20 @@ bits. In future examples, we may annotate the type in a comment. The examples will look like this: -```{rust} +```rust fn main() { let x = 5; // x: i32 } ``` -Note the similarities between this annotation and the syntax you use with `let`. -Including these kinds of comments is not idiomatic Rust, but we'll occasionally -include them to help you understand what the types that Rust infers are. +Note the similarities between this annotation and the syntax you use with +`let`. Including these kinds of comments is not idiomatic Rust, but we'll +occasionally include them to help you understand what the types that Rust +infers are. By default, bindings are *immutable*. This code will not compile: -```{ignore} +```rust,ignore let x = 5; x = 10; ``` @@ -75,30 +80,30 @@ error: re-assignment of immutable variable `x` If you want a binding to be mutable, you can use `mut`: -```{rust} +```rust let mut x = 5; // mut x: i32 x = 10; ``` There is no single reason that bindings are immutable by default, but we can -think about it through one of Rust's primary focuses: safety. If you forget to +think about it through one of Rust’s primary focuses: safety. If you forget to say `mut`, the compiler will catch it, and let you know that you have mutated something you may not have intended to mutate. If bindings were mutable by default, the compiler would not be able to tell you this. If you _did_ intend mutation, then the solution is quite easy: add `mut`. -There are other good reasons to avoid mutable state when possible, but they're +There are other good reasons to avoid mutable state when possible, but they’re out of the scope of this guide. In general, you can often avoid explicit mutation, and so it is preferable in Rust. That said, sometimes, mutation is -what you need, so it's not verboten. +what you need, so it’s not verboten. -Let's get back to bindings. Rust variable bindings have one more aspect that +Let’s get back to bindings. Rust variable bindings have one more aspect that differs from other languages: bindings are required to be initialized with a value before you're allowed to use them. -Let's try it out. Change your `src/main.rs` file to look like this: +Let’s try it out. Change your `src/main.rs` file to look like this: -```{rust} +```rust fn main() { let x: i32; @@ -106,21 +111,22 @@ fn main() { } ``` -You can use `cargo build` on the command line to build it. You'll get a warning, -but it will still print "Hello, world!": +You can use `cargo build` on the command line to build it. You’ll get a +warning, but it will still print "Hello, world!": ```text Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) -src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] on by default +src/main.rs:2:9: 2:10 warning: unused variable: `x`, #[warn(unused_variable)] + on by default src/main.rs:2 let x: i32; ^ ``` -Rust warns us that we never use the variable binding, but since we never use it, -no harm, no foul. Things change if we try to actually use this `x`, however. Let's -do that. Change your program to look like this: +Rust warns us that we never use the variable binding, but since we never use +it, no harm, no foul. Things change if we try to actually use this `x`, +however. Let’s do that. Change your program to look like this: -```{rust,ignore} +```rust,ignore fn main() { let x: i32; @@ -128,9 +134,9 @@ fn main() { } ``` -And try to build it. You'll get an error: +And try to build it. You’ll get an error: -```{bash} +```bash $ cargo build Compiling hello_world v0.0.1 (file:///home/you/projects/hello_world) src/main.rs:4:39: 4:40 error: use of possibly uninitialized variable: `x` @@ -144,18 +150,20 @@ error: aborting due to previous error Could not compile `hello_world`. ``` -Rust will not let us use a value that has not been initialized. Next, let's +Rust will not let us use a value that has not been initialized. Next, let’s talk about this stuff we've added to `println!`. If you include two curly braces (`{}`, some call them moustaches...) in your string to print, Rust will interpret this as a request to interpolate some sort of value. *String interpolation* is a computer science term that means "stick in the middle of a string." We add a comma, and then `x`, to indicate that we -want `x` to be the value we're interpolating. The comma is used to separate -arguments we pass to functions and macros, if you're passing more than one. - -When you just use the curly braces, Rust will attempt to display the -value in a meaningful way by checking out its type. If you want to specify the -format in a more detailed manner, there are a [wide number of options -available](../std/fmt/index.html). For now, we'll just stick to the default: -integers aren't very complicated to print. +want `x` to be the value we’re interpolating. The comma is used to separate +arguments we pass to functions and macros, if you’re passing more than one. + +When you just use the curly braces, Rust will attempt to display the value in a +meaningful way by checking out its type. If you want to specify the format in a +more detailed manner, there are a [wide number of options available][format]. +For now, we'll just stick to the default: integers aren't very complicated to +print. + +[format]: ../std/fmt/index.html diff --git a/src/doc/trpl/vectors.md b/src/doc/trpl/vectors.md new file mode 100644 index 0000000000..0dfbfc1191 --- /dev/null +++ b/src/doc/trpl/vectors.md @@ -0,0 +1,32 @@ +% Vectors + +A *vector* is a dynamic or "growable" array, implemented as the standard +library type [`Vec`](../std/vec/) (Where `` is a [Generic](./generics.md) statement). Vectors always allocate their data on the heap. Vectors are to slices +what `String` is to `&str`. You can create them with the `vec!` macro: + +```{rust} +let v = vec![1, 2, 3]; // v: Vec +``` + +(Notice that unlike the `println!` macro we've used in the past, we use square +brackets `[]` with `vec!`. Rust allows you to use either in either situation, +this is just convention.) + +There's an alternate form of `vec!` for repeating an initial value: + +``` +let v = vec![0; 10]; // ten zeroes +``` + +You can get the length of, iterate over, and subscript vectors just like +arrays. In addition, (mutable) vectors can grow automatically: + +```{rust} +let mut nums = vec![1, 2, 3]; // mut nums: Vec + +nums.push(4); + +println!("The length of nums is now {}", nums.len()); // Prints 4 +``` + +Vectors have many more useful methods. diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md new file mode 100644 index 0000000000..f2e2f6b6f4 --- /dev/null +++ b/src/doc/trpl/while-loops.md @@ -0,0 +1,93 @@ +% while loops + +Rust also has a `while` loop. It looks like this: + +```{rust} +let mut x = 5; // mut x: u32 +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/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 4e489df7dd..fc4d15a516 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -9,6 +9,7 @@ # except according to those terms. import gdb +import re #=============================================================================== # GDB Pretty Printing Module for Rust @@ -299,12 +300,12 @@ def classify_struct(type): if fields[0].name == "RUST$ENUM$DISR": if field_count == 1: return STRUCT_KIND_CSTYLE_VARIANT - elif fields[1].name is None: + elif all_fields_conform_to_tuple_field_naming(fields, 1): return STRUCT_KIND_TUPLE_VARIANT else: return STRUCT_KIND_STRUCT_VARIANT - if fields[0].name is None: + if all_fields_conform_to_tuple_field_naming(fields, 0): if type.tag.startswith("("): return STRUCT_KIND_TUPLE else: @@ -325,7 +326,6 @@ def first_field(val): for field in val.type.fields(): return field - def get_field_at_index(val, index): i = 0 for field in val.type.fields(): @@ -334,6 +334,12 @@ def get_field_at_index(val, index): i += 1 return None +def all_fields_conform_to_tuple_field_naming(fields, start_index): + for i in range(start_index, len(fields)): + if (fields[i].name is None) or (re.match(r"__\d+$", fields[i].name) is None): + return False + return True + def extract_length_and_data_ptr_from_std_vec(vec_val): length = int(vec_val["len"]) vec_ptr_val = vec_val["ptr"] diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index a212e3a043..2acee8a97f 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -186,7 +186,8 @@ def concat_multi_lines(f): firstlineno = firstlineno or lineno if line.endswith('\\'): - lastline = line[:-1] + if lastline is None: + lastline = line[:-1] catenated += line[:-1] else: yield firstlineno, catenated + line diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index 20f9b1ce66..2aaa158875 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -9,7 +9,7 @@ # except according to those terms. import lldb - +import re def print_val(val, internal_dict): '''Prints the given value with Rust syntax''' @@ -61,14 +61,14 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict): # The only field of this struct is the enum discriminant return type_name - has_field_names = type_has_field_names(t) + is_tuple_like = type_is_tuple_like(t) - if has_field_names: - template = "%(type_name)s {\n%(body)s\n}" - separator = ", \n" - else: + if is_tuple_like: template = "%(type_name)s(%(body)s)" separator = ", " + else: + template = "%(type_name)s {\n%(body)s\n}" + separator = ", \n" if type_name.startswith("("): # this is a tuple, so don't print the type name @@ -76,7 +76,7 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict): def render_child(child_index): this = "" - if has_field_names: + if not is_tuple_like: field_name = t.GetFieldAtIndex(child_index).GetName() this += field_name + ": " @@ -233,13 +233,15 @@ def extract_type_name(qualified_type_name): return qualified_type_name[index + 2:] -def type_has_field_names(ty): +def type_is_tuple_like(ty): '''Returns true of this is a type with field names (struct, struct-like enum variant)''' - # This may also be an enum variant where the first field doesn't have a name but the rest has - if ty.GetNumberOfFields() > 1: - return ty.GetFieldAtIndex(1).GetName() is not None - else: - return ty.GetFieldAtIndex(0).GetName() is not None + for field in ty.fields: + if field.GetName() == "RUST$ENUM$DISR": + # Ignore the enum discriminant field if there is one. + continue + if (field.GetName() is None) or (re.match(r"__\d+$", field.GetName()) is None): + return False + return True def is_vec_slice(val): diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh deleted file mode 100755 index 918c0c66f7..0000000000 --- a/src/etc/rustup.sh +++ /dev/null @@ -1,615 +0,0 @@ -#!/bin/sh -# Copyright 2014 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. - - -msg() { - echo "rustup: $1" -} - -step_msg() { - msg - msg "$1" - msg -} - -warn() { - echo "rustup: WARNING: $1" -} - -err() { - echo "rustup: error: $1" - exit 1 -} - -need_ok() { - if [ $? -ne 0 ] - then - err "$1" - fi -} - - -putvar() { - local T - eval T=\$$1 - eval TLEN=\${#$1} - if [ $TLEN -gt 35 ] - then - printf "rustup: %-20s := %.35s ...\n" $1 "$T" - else - printf "rustup: %-20s := %s %s\n" $1 "$T" "$2" - fi -} - -probe() { - local V=$1 - shift - local P - local T - for P - do - T=$(which $P 2>&1) - if [ $? -eq 0 ] - then - VER0=$($P --version 2>/dev/null | head -1 \ - | sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' ) - if [ $? -eq 0 -a "x${VER0}" != "x" ] - then - VER="($VER0)" - else - VER="" - fi - break - else - VER="" - T="" - fi - done - eval $V=\$T - putvar $V "$VER" -} - -probe_need() { - local V=$1 - probe $* - eval VV=\$$V - if [ -z "$VV" ] - then - err "needed, but unable to find any of: $*" - fi -} - - -valopt() { - VAL_OPTIONS="$VAL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - if [ $HELP -eq 0 ] - then - local UOP=$(echo $OP | tr '[:lower:]' '[:upper:]' | tr '\-' '\_') - local V="CFG_${UOP}" - eval $V="$DEFAULT" - for arg in $CFG_ARGS - do - if echo "$arg" | grep -q -- "--$OP=" - then - val=$(echo "$arg" | cut -f2 -d=) - eval $V=$val - fi - done - putvar $V - else - if [ -z "$DEFAULT" ] - then - DEFAULT="" - fi - OP="${OP}=[${DEFAULT}]" - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -opt() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - local DEFAULT=$2 - shift - shift - local DOC="$*" - local FLAG="" - - if [ $DEFAULT -eq 0 ] - then - FLAG="enable" - else - FLAG="disable" - DOC="don't $DOC" - fi - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${FLAG}-${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - FLAG=$(echo $FLAG | tr 'a-z' 'A-Z') - local V="CFG_${FLAG}_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$FLAG-$OP" "$DOC" - fi -} - -flag() { - BOOL_OPTIONS="$BOOL_OPTIONS $1" - - local OP=$1 - shift - local DOC="$*" - - if [ $HELP -eq 0 ] - then - for arg in $CFG_ARGS - do - if [ "$arg" = "--${OP}" ] - then - OP=$(echo $OP | tr 'a-z-' 'A-Z_') - local V="CFG_${OP}" - eval $V=1 - putvar $V - fi - done - else - if [ ! -z "$META" ] - then - OP="$OP=<$META>" - fi - printf " --%-30s %s\n" "$OP" "$DOC" - fi -} - -validate_opt() { - for arg in $CFG_ARGS - do - isArgValid=0 - for option in $BOOL_OPTIONS - do - if test --disable-$option = $arg - then - isArgValid=1 - fi - if test --enable-$option = $arg - then - isArgValid=1 - fi - if test --$option = $arg - then - isArgValid=1 - fi - done - for option in $VAL_OPTIONS - do - if echo "$arg" | grep -q -- "--$option=" - then - isArgValid=1 - fi - done - if [ "$arg" = "--help" ] - then - echo - echo "No more help available for Configure options," - echo "check the Wiki or join our IRC channel" - break - else - if test $isArgValid -eq 0 - then - err "Option '$arg' is not recognized" - fi - fi - done -} - -create_tmp_dir() { - local TMP_DIR=`pwd`/rustup-tmp-install - - rm -Rf "${TMP_DIR}" - need_ok "failed to remove temporary installation directory" - - mkdir -p "${TMP_DIR}" - need_ok "failed to create create temporary installation directory" - - echo $TMP_DIR -} - -# Make `tr` locale independent -LC_CTYPE=C - -probe_need CFG_CURL curl -probe_need CFG_TAR tar -probe_need CFG_FILE file - -probe CFG_SHA256SUM sha256sum -probe CFG_SHASUM shasum - -if [ -z "$CFG_SHA256SUM" -a -z "$CFG_SHASUM" ]; then - err "unable to find either sha256sum or shasum" -fi - -calculate_hash() { - if [ -n "$CFG_SHA256SUM" ]; then - ${CFG_SHA256SUM} $@ - else - ${CFG_SHASUM} -a 256 $@ - fi -} - -CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/" -CFG_SELF="$0" -CFG_ARGS="$@" - -HELP=0 -if [ "$1" = "--help" ] -then - HELP=1 - shift - echo - echo "Usage: $CFG_SELF [options]" - echo - echo "Options:" - echo -else - step_msg "processing $CFG_SELF args" -fi - -OPTIONS="" -BOOL_OPTIONS="" -VAL_OPTIONS="" - -flag uninstall "only uninstall from the installation prefix" -valopt prefix "" "set installation prefix" -valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" -valopt channel "beta" "use the selected release channel [beta]" -flag save "save the downloaded nightlies to ~/.rustup" - -if [ $HELP -eq 1 ] -then - echo - exit 0 -fi - -step_msg "validating $CFG_SELF args" -validate_opt - - -# Platform detection copied from `configure` - -CFG_OSTYPE=$(uname -s) -CFG_CPUTYPE=$(uname -m) - -if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] -then - # Darwin's `uname -m` lies and always returns i386. We have to use sysctl - # instead. - if sysctl hw.optional.x86_64 | grep -q ': 1' - then - CFG_CPUTYPE=x86_64 - fi -fi - -# The goal here is to come up with the same triple as LLVM would, -# at least for the subset of platforms we're willing to target. - -case $CFG_OSTYPE in - - Linux) - CFG_OSTYPE=unknown-linux-gnu - ;; - - FreeBSD) - CFG_OSTYPE=unknown-freebsd - ;; - - Darwin) - CFG_OSTYPE=apple-darwin - ;; - - MINGW32*) - CFG_OSTYPE=pc-mingw32 - ;; -# Thad's Cygwin identifiers below - -# Vista 32 bit - CYGWIN_NT-6.0) - CFG_OSTYPE=pc-mingw32 - CFG_CPUTYPE=i686 - ;; - -# Vista 64 bit - CYGWIN_NT-6.0-WOW64) - CFG_OSTYPE=w64-mingw32 - CFG_CPUTYPE=x86_64 - ;; - -# Win 7 32 bit - CYGWIN_NT-6.1) - CFG_OSTYPE=pc-mingw32 - CFG_CPUTYPE=i686 - ;; - -# Win 7 64 bit - CYGWIN_NT-6.1-WOW64) - CFG_OSTYPE=w64-mingw32 - CFG_CPUTYPE=x86_64 - ;; - -# We do not detect other OS such as XP/2003 using 64 bit using uname. -# If we want to in the future, we will need to use Cygwin -# Chuck's csih helper in /usr/lib/csih/winProductName.exe or alternative. - *) - err "unknown OS type: $CFG_OSTYPE" - ;; -esac - - -case $CFG_CPUTYPE in - - i386 | i486 | i686 | i786 | x86) - CFG_CPUTYPE=i686 - ;; - - xscale | arm) - CFG_CPUTYPE=arm - ;; - - x86_64 | x86-64 | x64 | amd64) - CFG_CPUTYPE=x86_64 - ;; - - *) - err "unknown CPU type: $CFG_CPUTYPE" -esac - -# Detect 64 bit linux systems with 32 bit userland and force 32 bit compilation -if [ $CFG_OSTYPE = unknown-linux-gnu -a $CFG_CPUTYPE = x86_64 ] -then - "${CFG_FILE}" -L "$SHELL" | grep -q "x86[_-]64" - if [ $? != 0 ]; then - CFG_CPUTYPE=i686 - fi -fi - -HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}" - -# Is this a triple we have nightlies for? -case $HOST_TRIPLE in - - x86_64-unknown-linux-gnu) - ;; - - i686-unknown-linux-gnu) - ;; - - x86_64-apple-darwin) - ;; - - i686-apple-darwin) - ;; - - *) - err "rustup.sh doesn't work for host $HOST_TRIPLE" - -esac - -msg "host triple: ${HOST_TRIPLE}" - -CFG_INSTALL_FLAGS="" -if [ -n "${CFG_UNINSTALL}" ] -then - CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --uninstall" -fi - -if [ -n "${CFG_PREFIX}" ] -then - CFG_INSTALL_FLAGS="${CFG_INSTALL_FLAGS} --prefix=${CFG_PREFIX}" -fi - -CFG_TMP_DIR=$(mktemp -d 2>/dev/null \ - || mktemp -d -t 'rustup-tmp-install' 2>/dev/null \ - || create_tmp_dir) - -# If we're saving nightlies and we didn't specify which one, grab the latest -# version from the perspective of the server. Buildbot has typically finished -# building and uploading by ~8UTC, but we want to include a little buffer. -# -# FIXME It would be better to use the known most recent nightly that has been -# built. This is waiting on a change to have buildbot publish metadata that -# can be queried. -if [ -n "${CFG_SAVE}" -a -z "${CFG_DATE}" ]; -then - CFG_DATE=`TZ=Etc/UTC+9 date "+%Y-%m-%d"` -fi - -RUST_URL="https://static.rust-lang.org/dist" -case "$CFG_CHANNEL" in - nightly) - # add a date suffix if we want a particular nightly. - if [ -n "${CFG_DATE}" ]; - then - RUST_URL="${RUST_URL}/${CFG_DATE}" - fi - - RUST_PACKAGE_NAME=rust-nightly - ;; - beta) - RUST_PACKAGE_NAME=rust-1.0.0-beta - ;; - *) - err "Currently 'beta' and 'nightly' are the only supported channels" -esac - -RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}" -RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz" -RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}" -RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh" - -download_hash() { - msg "Downloading ${remote_sha256}" - remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"` - if [ -n "${CFG_SAVE}" ]; then - echo "${remote_sha256}" > "${local_sha_file}" - fi - if [ "$?" -ne 0 ]; then - rm -Rf "${CFG_TMP_DIR}" - err "Failed to download ${remote_url}" - fi -} - -verify_hash() { - remote_sha256="$1" - local_file="$2" - local_sha_file="${local_file}.sha256" - - if [ -n "${CFG_SAVE}" ]; then - if [ -f "${local_sha_file}" ]; then - msg "Local ${local_sha_file} exists, treating as remote hash" - remote_sha256=`cat "${local_sha_file}"` - else - download_hash - fi - else - download_hash - fi - - msg "Verifying hash" - local_sha256=$(calculate_hash "${local_file}") - if [ "$?" -ne 0 ]; then - rm -Rf "${CFG_TMP_DIR}" - err "Failed to compute hash for ${local_tarball}" - fi - - # We only need the sha, not the filenames - remote_sha256=`echo ${remote_sha256} | cut -f 1 -d ' '` - local_sha256=`echo ${local_sha256} | cut -f 1 -d ' '` - - if [ "${remote_sha256}" != "${local_sha256}" ]; then - rm -Rf "${CFG_TMP_DIR}" - errmsg="invalid sha256.\n" - errmsg="$errmsg ${remote_sha256}\t${remote_tarball}\n" - errmsg="$errmsg ${local_sha256}\t${local_tarball}" - err "$errmsg" - fi -} - -# Fetch the package. Optionally caches the tarballs. -download_package() { - remote_tarball="$1" - local_tarball="$2" - remote_sha256="${remote_tarball}.sha256" - - # Check if we've already downloaded this file. - if [ -e "${local_tarball}.tmp" ]; then - msg "Resuming ${remote_tarball} to ${local_tarball}" - - "${CFG_CURL}" -f -C - -o "${local_tarball}.tmp" "${remote_tarball}" - if [ $? -ne 0 ] - then - rm -Rf "${CFG_TMP_DIR}" - err "failed to download installer" - fi - - mv "${local_tarball}.tmp" "${local_tarball}" - elif [ ! -e "${local_tarball}" ]; then - msg "Downloading ${remote_tarball} to ${local_tarball}" - - "${CFG_CURL}" -f -o "${local_tarball}.tmp" "${remote_tarball}" - if [ $? -ne 0 ] - then - rm -Rf "${CFG_TMP_DIR}" - err "failed to download installer" - fi - - mv "${local_tarball}.tmp" "${local_tarball}" - fi - - verify_hash "${remote_sha256}" "${local_tarball}" -} - -# Wrap all the commands needed to install a package. -install_package() { - local_tarball="$1" - install_script="$2" - - msg "Extracting ${local_tarball}" - (cd "${CFG_TMP_DIR}" && "${CFG_TAR}" -xzf "${local_tarball}") - if [ $? -ne 0 ]; then - rm -Rf "${CFG_TMP_DIR}" - err "failed to unpack installer" - fi - - sh "${install_script}" "${CFG_INSTALL_FLAGS}" - if [ $? -ne 0 ] - then - rm -Rf "${CFG_TMP_DIR}" - err "failed to install Rust" - fi -} - -# It's possible that curl could be interrupted partway though downloading -# `rustup.sh`, truncating the file. This could be especially bad if we were in -# the middle of a line that would run "rm -rf ". To protect against this, we -# wrap up the `rustup.sh` destructive functionality in this helper function, -# which we call as the last thing we do. This means we will not do anything -# unless we have the entire file downloaded. -install_packages() { - rm -Rf "${CFG_TMP_DIR}" - need_ok "failed to remove temporary installation directory" - - mkdir -p "${CFG_TMP_DIR}" - need_ok "failed to create create temporary installation directory" - - # If we're saving our nightlies, put them in $HOME/.rustup. - if [ -n "${CFG_SAVE}" ] - then - RUST_DOWNLOAD_DIR="${HOME}/.rustup/${CFG_DATE}" - else - RUST_DOWNLOAD_DIR="${CFG_TMP_DIR}" - fi - - mkdir -p "${RUST_DOWNLOAD_DIR}" - need_ok "failed to create create download directory" - - RUST_LOCAL_TARBALL="${RUST_DOWNLOAD_DIR}/${RUST_TARBALL_NAME}" - - download_package \ - "${RUST_URL}/${RUST_TARBALL_NAME}" \ - "${RUST_LOCAL_TARBALL}" - - install_package \ - "${RUST_LOCAL_TARBALL}" \ - "${RUST_LOCAL_INSTALL_SCRIPT}" - - rm -Rf "${CFG_TMP_DIR}" - need_ok "couldn't rm temporary installation directory" -} - -install_packages diff --git a/src/etc/snapshot.pyc b/src/etc/snapshot.pyc index 05ba658a918cee76555609ed16aecf423f43a1d3..256561ec3e9cf8776ab953dae6c9c052149451fd 100644 GIT binary patch delta 16 XcmaFw_uh}4`7>26+ItK;< delta 16 XcmaFw_uh}4`7 bool {\n" % cat) - f.write(" super::bsearch_range_table(c, %s_table)\n" % cat) - f.write(" }\n\n") - f.write("}\n\n") - -def emit_regex_module(f, cats, w_data): - f.write("pub mod regex {\n") - regex_class = "&'static [(char, char)]" - class_table = "&'static [(&'static str, %s)]" % regex_class - - emit_table(f, "UNICODE_CLASSES", cats, class_table, - pfun=lambda x: "(\"%s\",super::%s::%s_table)" % (x[0], x[1], x[0])) - - f.write(" pub const PERLD: %s = super::general_category::Nd_table;\n\n" - % regex_class) - f.write(" pub const PERLS: %s = super::property::White_Space_table;\n\n" - % regex_class) - - emit_table(f, "PERLW", w_data, regex_class) - + f.write(" pub fn %s(c: char) -> bool {\n" % cat) + f.write(" super::bsearch_range_table(c, %s_table)\n" % cat) + f.write(" }\n\n") f.write("}\n\n") def emit_conversions_module(f, lowerupper, upperlower): @@ -623,44 +585,21 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); (canon_decomp, compat_decomp, gencats, combines, lowerupper, upperlower) = load_unicode_data("UnicodeData.txt") want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"] - other_derived = ["Default_Ignorable_Code_Point", "Grapheme_Extend"] - derived = load_properties("DerivedCoreProperties.txt", want_derived + other_derived) + derived = load_properties("DerivedCoreProperties.txt", want_derived) scripts = load_properties("Scripts.txt", []) props = load_properties("PropList.txt", ["White_Space", "Join_Control", "Noncharacter_Code_Point"]) norm_props = load_properties("DerivedNormalizationProps.txt", ["Full_Composition_Exclusion"]) - # grapheme cluster category from DerivedCoreProperties - # the rest are defined below - grapheme_cats = {} - grapheme_cats["Extend"] = derived["Grapheme_Extend"] - del(derived["Grapheme_Extend"]) - # bsearch_range_table is used in all the property modules below emit_bsearch_range_table(rf) - # all of these categories will also be available as \p{} in libregex - allcats = [] + # category tables for (name, cat, pfuns) in ("general_category", gencats, ["N", "Cc"]), \ ("derived_property", derived, want_derived), \ - ("script", scripts, []), \ ("property", props, ["White_Space"]): emit_property_module(rf, name, cat, pfuns) - allcats.extend(map(lambda x: (x, name), cat)) - allcats.sort(key=lambda c: c[0]) - - # the \w regex corresponds to Alphabetic + Mark + Decimal_Number + - # Connector_Punctuation + Join-Control according to UTS#18 - # http://www.unicode.org/reports/tr18/#Compatibility_Properties - perl_words = [] - for cat in derived["Alphabetic"], gencats["M"], gencats["Nd"], \ - gencats["Pc"], props["Join_Control"]: - perl_words.extend(ungroup_cat(cat)) - perl_words = group_cat(perl_words) - - # emit lookup tables for \p{}, along with \d, \w, and \s for libregex - emit_regex_module(rf, allcats, perl_words) # normalizations and conversions module emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) @@ -691,34 +630,24 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s); ### grapheme cluster module # from http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Break_Property_Values - # Hangul syllable categories - want_hangul = ["L", "V", "T", "LV", "LVT"] - grapheme_cats.update(load_properties("HangulSyllableType.txt", want_hangul)) + grapheme_cats = load_properties("auxiliary/GraphemeBreakProperty.txt", []) # Control + # Note 1: # This category also includes Cs (surrogate codepoints), but Rust's `char`s are # Unicode Scalar Values only, and surrogates are thus invalid `char`s. - grapheme_cats["Control"] = set() - for cat in ["Zl", "Zp", "Cc", "Cf"]: - grapheme_cats["Control"] |= set(ungroup_cat(gencats[cat])) + # Thus, we have to remove Cs from the Control category + # Note 2: + # 0x0a and 0x0d (CR and LF) are not in the Control category for Graphemes. + # However, the Graphemes iterator treats these as a special case, so they + # should be included in grapheme_cats["Control"] for our implementation. grapheme_cats["Control"] = group_cat(list( - grapheme_cats["Control"] - - grapheme_control_exceptions - | (set(ungroup_cat(gencats["Cn"])) - & set(ungroup_cat(derived["Default_Ignorable_Code_Point"]))))) - - # Regional Indicator - grapheme_cats["RegionalIndicator"] = grapheme_regional_indicator - - # Prepend - "Currently there are no characters with this value" - # (from UAX#29, Unicode 7.0) - - # SpacingMark - grapheme_cats["SpacingMark"] = group_cat(list( - set(ungroup_cat(gencats["Mc"])) - - set(ungroup_cat(grapheme_cats["Extend"])) - | grapheme_spacingmark_extra - - set(ungroup_cat(grapheme_spacingmark_exceptions)))) + (set(ungroup_cat(grapheme_cats["Control"])) + | set(ungroup_cat(grapheme_cats["CR"])) + | set(ungroup_cat(grapheme_cats["LF"]))) + - set(ungroup_cat([surrogate_codepoints])))) + del(grapheme_cats["CR"]) + del(grapheme_cats["LF"]) grapheme_table = [] for cat in grapheme_cats: diff --git a/src/jemalloc/VERSION b/src/jemalloc/VERSION index 595434747d..be5a033576 100644 --- a/src/jemalloc/VERSION +++ b/src/jemalloc/VERSION @@ -1 +1 @@ -0.12.0-7693-g9854143cba679834bc4ef932858cd5303f015a0e +0.12.0-8312-g5241bf9c34d156ea6064367a33cbd7222eeb5789 diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 8b884c5650..554ca3ea53 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -77,7 +77,6 @@ use core::atomic; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::fmt; use core::cmp::Ordering; -use core::default::Default; use core::mem::{min_align_of, size_of}; use core::mem; use core::nonzero::NonZero; @@ -103,7 +102,7 @@ use heap::deallocate; /// use std::thread; /// /// fn main() { -/// let numbers: Vec<_> = (0..100u32).map(|i| i as f32).collect(); +/// let numbers: Vec<_> = (0..100u32).collect(); /// let shared_numbers = Arc::new(numbers); /// /// for _ in 0..10 { @@ -243,10 +242,9 @@ pub fn weak_count(this: &Arc) -> usize { this.inner().weak.load(SeqCst) - pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst) } -/// Try accessing a mutable reference to the contents behind an unique `Arc`. +/// Returns a mutable reference to the contained value if the `Arc` is unique. /// -/// The access is granted only if this is the only reference to the object. -/// Otherwise, `None` is returned. +/// Returns `None` if the `Arc` is not unique. /// /// # Examples /// @@ -254,16 +252,19 @@ pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst /// # #![feature(alloc)] /// extern crate alloc; /// # fn main() { -/// use alloc::arc; +/// use alloc::arc::{Arc, get_mut}; /// -/// let mut four = arc::Arc::new(4); +/// let mut x = Arc::new(3); +/// *get_mut(&mut x).unwrap() = 4; +/// assert_eq!(*x, 4); /// -/// arc::unique(&mut four).map(|num| *num = 5); +/// let _y = x.clone(); +/// assert!(get_mut(&mut x).is_none()); /// # } /// ``` #[inline] #[unstable(feature = "alloc")] -pub fn unique(this: &mut Arc) -> Option<&mut T> { +pub fn get_mut(this: &mut Arc) -> Option<&mut T> { if strong_count(this) == 1 && 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 @@ -272,7 +273,7 @@ pub fn unique(this: &mut Arc) -> Option<&mut T> { // reference to the inner data. let inner = unsafe { &mut **this._ptr }; Some(&mut inner.data) - }else { + } else { None } } @@ -347,7 +348,7 @@ impl Arc { self.inner().weak.load(SeqCst) != 1 { *self = Arc::new((**self).clone()) } - // As with `unique()`, the unsafety is ok because our reference was + // 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 = unsafe { &mut **self._ptr }; &mut inner.data @@ -446,7 +447,7 @@ impl Weak { /// ``` pub fn upgrade(&self) -> Option> { // We use a CAS loop to increment the strong count instead of a - // fetch_add because once the count hits 0 is must never be above 0. + // 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); @@ -666,6 +667,13 @@ impl fmt::Debug for Arc { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self._ptr, f) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { #[stable(feature = "rust1", since = "1.0.0")] @@ -691,7 +699,7 @@ mod tests { use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::thread; use std::vec::Vec; - use super::{Arc, Weak, weak_count, strong_count, unique}; + use super::{Arc, Weak, get_mut, weak_count, strong_count}; use std::sync::Mutex; struct Canary(*mut atomic::AtomicUsize); @@ -728,18 +736,16 @@ mod tests { } #[test] - fn test_arc_unique() { - let mut x = Arc::new(10); - assert!(unique(&mut x).is_some()); - { - let y = x.clone(); - assert!(unique(&mut x).is_none()); - } - { - let z = x.downgrade(); - assert!(unique(&mut x).is_none()); - } - assert!(unique(&mut x).is_some()); + fn test_arc_get_mut() { + 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()); + drop(y); + assert!(get_mut(&mut x).is_some()); + let _w = x.downgrade(); + assert!(get_mut(&mut x).is_none()); } #[test] diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 2801cf38cb..7696abd659 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -10,14 +10,9 @@ //! A pointer type for heap allocation. //! -//! `Box`, casually referred to as a 'box', provides the simplest form of -//! heap allocation in Rust. Boxes provide ownership for this allocation, and -//! drop their contents when they go out of scope. -//! -//! Boxes are useful in two situations: recursive data structures, and -//! occasionally when returning data. [The Pointer chapter of the -//! Book](../../../book/pointers.html#best-practices-1) explains these cases in -//! detail. +//! `Box`, casually referred to as a 'box', provides the simplest form of heap allocation in +//! Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of +//! scope. //! //! # Examples //! @@ -43,6 +38,16 @@ //! ``` //! //! This will print `Cons(1, Box(Cons(2, Box(Nil))))`. +//! +//! Recursive structures must be boxed, because if the definition of `Cons` looked like this: +//! +//! ```rust,ignore +//! Cons(T, List), +//! ``` +//! +//! It wouldn't work. This is because the size of a `List` depends on how many elements are in the +//! list, and so we don't know how much memory to allocate for a `Cons`. By introducing a `Box`, +//! which has a defined size, we know how big `Cons` needs to be. #![stable(feature = "rust1", since = "1.0.0")] @@ -50,7 +55,6 @@ use core::prelude::*; use core::any::Any; use core::cmp::Ordering; -use core::default::Default; use core::fmt; use core::hash::{self, Hash}; use core::mem; @@ -275,6 +279,16 @@ impl fmt::Debug for Box { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Box { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // It's not possible to extract the inner Uniq directly from the Box, + // instead we cast it to a *const which aliases the Unique + let ptr: *const T = &**self; + fmt::Pointer::fmt(&ptr, f) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Box { type Target = T; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 7cdd488842..2ee229ab1d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -324,7 +324,7 @@ pub fn try_unwrap(rc: Rc) -> Result> { /// ``` #[inline] #[unstable(feature = "alloc")] -pub fn get_mut<'a, T>(rc: &'a mut Rc) -> Option<&'a mut T> { +pub fn get_mut(rc: &mut Rc) -> Option<&mut T> { if is_unique(rc) { let inner = unsafe { &mut **rc._ptr }; Some(&mut inner.value) @@ -459,7 +459,6 @@ impl Default for Rc { /// /// ``` /// use std::rc::Rc; - /// use std::default::Default; /// /// let x: Rc = Default::default(); /// ``` @@ -634,6 +633,13 @@ impl fmt::Debug for Rc { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self._ptr, f) + } +} + /// A weak version of `Rc`. /// /// Weak references do not count when determining if the inner value should be diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7843be0b48..e190fb4222 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -192,13 +192,16 @@ struct TyDesc { align: usize } +trait AllTypes { fn dummy(&self) { } } +impl AllTypes for T { } + unsafe fn get_tydesc() -> *const TyDesc { use std::raw::TraitObject; let ptr = &*(1 as *const T); // Can use any trait that is implemented for all types. - let obj = mem::transmute::<&marker::MarkerTrait, TraitObject>(ptr); + let obj = mem::transmute::<&AllTypes, TraitObject>(ptr); obj.vtable as *const TyDesc } @@ -359,10 +362,6 @@ fn test_arena_destructors_fail() { } /// A faster arena that can hold objects of only one type. -/// -/// Safety note: Modifying objects in the arena that have already had their -/// `drop` destructors run can cause leaks, because the destructor will not -/// run again for these objects. pub struct TypedArena { /// A pointer to the next object to be allocated. ptr: Cell<*const T>, diff --git a/src/libbacktrace/ChangeLog b/src/libbacktrace/ChangeLog index 5ad616228e..e385d8f741 100644 --- a/src/libbacktrace/ChangeLog +++ b/src/libbacktrace/ChangeLog @@ -1,3 +1,56 @@ +2015-01-24 Matthias Klose + + * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. + * configure: Regenerate. + +2015-01-05 Jakub Jelinek + + Update copyright years. + +2014-11-21 H.J. Lu + + PR bootstrap/63784 + * configure: Regenerated. + +2014-11-11 David Malcolm + + * ChangeLog.jit: New. + +2014-11-11 Francois-Xavier Coudert + + PR target/63610 + * configure: Regenerate. + +2014-10-23 Ian Lance Taylor + + * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: + Fix to return void *. + +2014-05-08 Ian Lance Taylor + + * mmap.c (backtrace_free): If freeing a large aligned block of + memory, call munmap rather than holding onto it. + (backtrace_vector_grow): When growing a vector, double the number + of pages requested. When releasing the old version of a grown + vector, pass the correct size to backtrace_free. + +2014-03-07 Ian Lance Taylor + + * sort.c (backtrace_qsort): Use middle element as pivot. + +2014-03-06 Ian Lance Taylor + + * sort.c: New file. + * stest.c: New file. + * internal.h (backtrace_qsort): Declare. + * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. + (read_line_info, read_function_entry): Likewise. + (read_function_info, build_dwarf_data): Likewise. + * elf.c (elf_initialize_syminfo): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. + (stest_SOURCES, stest_LDADD): Define. + (check_PROGRAMS): Add stest. + 2014-02-07 Misty De Meo PR target/58710 diff --git a/src/libbacktrace/ChangeLog.jit b/src/libbacktrace/ChangeLog.jit new file mode 100644 index 0000000000..6b60e3b3b0 --- /dev/null +++ b/src/libbacktrace/ChangeLog.jit @@ -0,0 +1,14 @@ +2014-09-24 David Malcolm + + * ChangeLog.jit: Add copyright footer. + +2013-10-03 David Malcolm + + * configure.ac: Add --enable-host-shared. + * configure: Regenerate. + +Copyright (C) 2013-2014 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/src/libbacktrace/Makefile.am b/src/libbacktrace/Makefile.am index 4372899829..a93b82a91b 100644 --- a/src/libbacktrace/Makefile.am +++ b/src/libbacktrace/Makefile.am @@ -1,17 +1,17 @@ # Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# Copyright (C) 2012-2015 Free Software Foundation, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. +# distribution. # (3) The name of the author may not be used to # endorse or promote products derived from this software without @@ -46,6 +46,7 @@ libbacktrace_la_SOURCES = \ internal.h \ posix.c \ print.c \ + sort.c \ state.c BACKTRACE_FILES = \ @@ -93,6 +94,11 @@ btest_LDADD = libbacktrace.la check_PROGRAMS += btest +stest_SOURCES = stest.c +stest_LDADD = libbacktrace.la + +check_PROGRAMS += stest + endif NATIVE # We can't use automake's automatic dependency tracking, because it diff --git a/src/libbacktrace/Makefile.in b/src/libbacktrace/Makefile.in index 93ccec2dbf..f2821fc152 100644 --- a/src/libbacktrace/Makefile.in +++ b/src/libbacktrace/Makefile.in @@ -23,12 +23,12 @@ # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. +# distribution. # (3) The name of the author may not be used to # endorse or promote products derived from this software without @@ -67,7 +67,7 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ check_PROGRAMS = $(am__EXEEXT_1) -@NATIVE_TRUE@am__append_1 = btest +@NATIVE_TRUE@am__append_1 = btest stest subdir = . DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/configure \ @@ -94,15 +94,18 @@ CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ - print.lo state.lo + print.lo sort.lo state.lo libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) -@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) +@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) btest_OBJECTS = $(am_btest_OBJECTS) @NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ +@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) +stest_OBJECTS = $(am_stest_OBJECTS) +@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = am__depfiles_maybe = @@ -116,11 +119,11 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ - $(btest_SOURCES) -MULTISRCTOP = -MULTIBUILDTOP = -MULTIDIRS = -MULTISUBDIR = + $(btest_SOURCES) $(stest_SOURCES) +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = MULTIDO = true MULTICLEAN = true ETAGS = etags @@ -264,6 +267,7 @@ libbacktrace_la_SOURCES = \ internal.h \ posix.c \ print.c \ + sort.c \ state.c BACKTRACE_FILES = \ @@ -300,6 +304,8 @@ TESTS = $(check_PROGRAMS) @NATIVE_TRUE@btest_SOURCES = btest.c @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O @NATIVE_TRUE@btest_LDADD = libbacktrace.la +@NATIVE_TRUE@stest_SOURCES = stest.c +@NATIVE_TRUE@stest_LDADD = libbacktrace.la # We can't use automake's automatic dependency tracking, because it # breaks when using bootstrap-lean. Automatic dependency tracking @@ -362,7 +368,7 @@ config.h: stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ @@ -380,7 +386,7 @@ clean-noinstLTLIBRARIES: echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done -libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) +libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS) clean-checkPROGRAMS: @@ -391,9 +397,12 @@ clean-checkPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list -btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) +btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) @rm -f btest$(EXEEXT) $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) +stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) + @rm -f stest$(EXEEXT) + $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) diff --git a/src/libbacktrace/alloc.c b/src/libbacktrace/alloc.c index 4aa85d050f..143ef68ca5 100644 --- a/src/libbacktrace/alloc.c +++ b/src/libbacktrace/alloc.c @@ -1,5 +1,5 @@ /* alloc.c -- Memory allocation without mmap. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/atomic.c b/src/libbacktrace/atomic.c index b31fa64c79..fdd2490da7 100644 --- a/src/libbacktrace/atomic.c +++ b/src/libbacktrace/atomic.c @@ -1,5 +1,5 @@ /* atomic.c -- Support for atomic functions if not present. - Copyright (C) 2013-2014 Free Software Foundation, Inc. + Copyright (C) 2013-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace-supported.h.in b/src/libbacktrace/backtrace-supported.h.in index 28488167c4..5115ce1e61 100644 --- a/src/libbacktrace/backtrace-supported.h.in +++ b/src/libbacktrace/backtrace-supported.h.in @@ -1,5 +1,5 @@ /* backtrace-supported.h.in -- Whether stack backtrace is supported. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace.c b/src/libbacktrace/backtrace.c index 4b90357df5..d352d27a40 100644 --- a/src/libbacktrace/backtrace.c +++ b/src/libbacktrace/backtrace.c @@ -1,5 +1,5 @@ /* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/backtrace.h b/src/libbacktrace/backtrace.h index 3f77093f76..50dcd40751 100644 --- a/src/libbacktrace/backtrace.h +++ b/src/libbacktrace/backtrace.h @@ -1,5 +1,5 @@ /* backtrace.h -- Public header file for stack backtrace library. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/btest.c b/src/libbacktrace/btest.c index a1818f1ef8..9424a927f2 100644 --- a/src/libbacktrace/btest.c +++ b/src/libbacktrace/btest.c @@ -1,5 +1,5 @@ /* btest.c -- Test for libbacktrace library - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -460,7 +460,7 @@ f23 (int f1line, int f2line) (unsigned int) bdata.index, j + 1); bdata.failed = 1; } - } + } check ("test3", 0, all, f3line, "f23", &bdata.failed); check ("test3", 1, all, f2line, "f22", &bdata.failed); diff --git a/src/libbacktrace/configure b/src/libbacktrace/configure index d5e08d93f6..deedfebd66 100755 --- a/src/libbacktrace/configure +++ b/src/libbacktrace/configure @@ -614,7 +614,6 @@ PIC_FLAG WARN_FLAGS EXTRA_FLAGS BACKTRACE_FILE -multi_basedir OTOOL64 OTOOL LIPO @@ -680,6 +679,7 @@ build_os build_vendor build_cpu build +multi_basedir target_alias host_alias build_alias @@ -721,6 +721,7 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking +enable_multilib enable_maintainer_mode with_target_subdir enable_shared @@ -729,7 +730,6 @@ with_pic enable_fast_install with_gnu_ld enable_libtool_lock -enable_multilib with_system_libunwind enable_host_shared ' @@ -1362,6 +1362,7 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-multilib build many library versions (default) --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-shared[=PKGS] build shared libraries [default=no] @@ -1369,7 +1370,6 @@ Optional Features: --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) - --enable-multilib build many library versions (default) --enable-host-shared build host code as shared libraries Optional Packages: @@ -2453,6 +2453,46 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" +if test -n "${with_target_subdir}"; then + # Default to --enable-multilib +# Check whether --enable-multilib was given. +if test "${enable_multilib+set}" = set; then : + enableval=$enable_multilib; case "$enableval" in + yes) multilib=yes ;; + no) multilib=no ;; + *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;; + esac +else + multilib=yes +fi + + +# We may get other options which we leave undocumented: +# --with-target-subdir, --with-multisrctop, --with-multisubdir +# See config-ml.in if you want the gory details. + +if test "$srcdir" = "."; then + if test "$with_target_subdir" != "."; then + multi_basedir="$srcdir/$with_multisrctop../.." + else + multi_basedir="$srcdir/$with_multisrctop.." + fi +else + multi_basedir="$srcdir/.." +fi + + +# Even if the default multilib is not a cross compilation, +# it may be that some of the other multilibs are. +if test $cross_compiling = no && test $multilib = yes \ + && test "x${with_multisubdir}" != x ; then + cross_compiling=maybe +fi + +ac_config_commands="$ac_config_commands default-1" + +fi + ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do for ac_t in install-sh install.sh shtool; do @@ -7576,7 +7616,7 @@ $as_echo "$lt_cv_ld_force_load" >&6; } case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - 10.[012]*) + 10.[012][,.]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; @@ -8879,7 +8919,7 @@ _LT_EOF if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then - tmp_addflag= + tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler @@ -11089,7 +11129,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11092 "configure" +#line 11132 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11195,7 +11235,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11198 "configure" +#line 11238 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11439,43 +11479,6 @@ backtrace_supported=yes if test -n "${with_target_subdir}"; then # We are compiling a GCC library. We can assume that the unwind # library exists. - # Default to --enable-multilib -# Check whether --enable-multilib was given. -if test "${enable_multilib+set}" = set; then : - enableval=$enable_multilib; case "$enableval" in - yes) multilib=yes ;; - no) multilib=no ;; - *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;; - esac -else - multilib=yes -fi - - -# We may get other options which we leave undocumented: -# --with-target-subdir, --with-multisrctop, --with-multisubdir -# See config-ml.in if you want the gory details. - -if test "$srcdir" = "."; then - if test "$with_target_subdir" != "."; then - multi_basedir="$srcdir/$with_multisrctop../.." - else - multi_basedir="$srcdir/$with_multisrctop.." - fi -else - multi_basedir="$srcdir/.." -fi - - -# Even if the default multilib is not a cross compilation, -# it may be that some of the other multilibs are. -if test $cross_compiling = no && test $multilib = yes \ - && test "x${with_multisubdir}" != x ; then - cross_compiling=maybe -fi - -ac_config_commands="$ac_config_commands default-1" - BACKTRACE_FILE="backtrace.lo simple.lo" else ac_fn_c_check_header_mongrel "$LINENO" "unwind.h" "ac_cv_header_unwind_h" "$ac_includes_default" @@ -13174,6 +13177,20 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # INIT-COMMANDS # +srcdir="$srcdir" +host="$host" +target="$target" +with_multisubdir="$with_multisubdir" +with_multisrctop="$with_multisrctop" +with_target_subdir="$with_target_subdir" +ac_configure_args="${multilib_arg} ${ac_configure_args}" +multi_basedir="$multi_basedir" +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} +CC="$CC" +CXX="$CXX" +GFORTRAN="$GFORTRAN" +GCJ="$GCJ" + # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. @@ -13434,20 +13451,6 @@ fi -srcdir="$srcdir" -host="$host" -target="$target" -with_multisubdir="$with_multisubdir" -with_multisrctop="$with_multisrctop" -with_target_subdir="$with_target_subdir" -ac_configure_args="${multilib_arg} ${ac_configure_args}" -multi_basedir="$multi_basedir" -CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} -CC="$CC" -CXX="$CXX" -GFORTRAN="$GFORTRAN" -GCJ="$GCJ" - GCC="$GCC" CC="$CC" acx_cv_header_stdint="$acx_cv_header_stdint" @@ -13480,8 +13483,8 @@ for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "gstdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS gstdint.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "backtrace-supported.h") CONFIG_FILES="$CONFIG_FILES backtrace-supported.h" ;; @@ -14070,6 +14073,14 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} case $ac_file$ac_mode in + "default-1":C) +# Only add multilib support code if we just rebuilt the top-level +# Makefile. +case " $CONFIG_FILES " in + *" Makefile "*) + ac_file=Makefile . ${multi_basedir}/config-ml.in + ;; +esac ;; "libtool":C) # See if we are running on zsh, and set the options which allow our @@ -14709,14 +14720,6 @@ _LT_EOF chmod +x "$ofile" ;; - "default-1":C) -# Only add multilib support code if we just rebuilt the top-level -# Makefile. -case " $CONFIG_FILES " in - *" Makefile "*) - ac_file=Makefile . ${multi_basedir}/config-ml.in - ;; -esac ;; "gstdint.h":C) if test "$GCC" = yes; then echo "/* generated for " `$CC --version | sed 1q` "*/" > tmp-stdint.h @@ -15153,3 +15156,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/src/libbacktrace/configure.ac b/src/libbacktrace/configure.ac index d661c7b256..9c37dac43a 100644 --- a/src/libbacktrace/configure.ac +++ b/src/libbacktrace/configure.ac @@ -1,18 +1,18 @@ # configure.ac -- Backtrace configure script. -# Copyright (C) 2012-2014 Free Software Foundation, Inc. +# Copyright (C) 2012-2015 Free Software Foundation, Inc. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. +# notice, this list of conditions and the following disclaimer. # (2) Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the -# distribution. - +# distribution. + # (3) The name of the author may not be used to # endorse or promote products derived from this software without # specific prior written permission. @@ -34,6 +34,10 @@ AC_INIT(package-unused, version-unused,, libbacktrace) AC_CONFIG_SRCDIR(backtrace.h) AC_CONFIG_HEADER(config.h) +if test -n "${with_target_subdir}"; then + AM_ENABLE_MULTILIB(, ..) +fi + AC_CANONICAL_SYSTEM target_alias=${target_alias-$host_alias} @@ -83,7 +87,6 @@ backtrace_supported=yes if test -n "${with_target_subdir}"; then # We are compiling a GCC library. We can assume that the unwind # library exists. - AM_ENABLE_MULTILIB(, ..) BACKTRACE_FILE="backtrace.lo simple.lo" else AC_CHECK_HEADER([unwind.h], diff --git a/src/libbacktrace/dwarf.c b/src/libbacktrace/dwarf.c index 5ecae71179..919b568c78 100644 --- a/src/libbacktrace/dwarf.c +++ b/src/libbacktrace/dwarf.c @@ -1,5 +1,5 @@ /* dwarf.c -- Get file/line information from DWARF for backtraces. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -1134,8 +1134,8 @@ read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, ++num_abbrevs; } - qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, sizeof (struct abbrev), - abbrev_compare); + backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); return 1; @@ -1241,7 +1241,7 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, static int find_address_ranges (struct backtrace_state *state, uintptr_t base_address, - struct dwarf_buf *unit_buf, + struct dwarf_buf *unit_buf, const unsigned char *dwarf_str, size_t dwarf_str_size, const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, @@ -1599,7 +1599,7 @@ read_line_header (struct backtrace_state *state, struct unit *u, if (!advance (line_buf, hdrlen)) return 0; - + hdr->min_insn_len = read_byte (&hdr_buf); if (hdr->version < 4) hdr->max_ops_per_insn = 1; @@ -1608,7 +1608,7 @@ read_line_header (struct backtrace_state *state, struct unit *u, /* We don't care about default_is_stmt. */ read_byte (&hdr_buf); - + hdr->line_base = read_sbyte (&hdr_buf); hdr->line_range = read_byte (&hdr_buf); @@ -2016,7 +2016,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, goto fail; ln = (struct line *) vec.vec.base; - qsort (ln, vec.count, sizeof (struct line), line_compare); + backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); *lines = ln; *lines_count = vec.count; @@ -2476,9 +2476,9 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, return 0; faddrs = (struct function_addrs *) fvec.vec.base; - qsort (faddrs, fvec.count, - sizeof (struct function_addrs), - function_addrs_compare); + backtrace_qsort (faddrs, fvec.count, + sizeof (struct function_addrs), + function_addrs_compare); function->function_addrs = faddrs; function->function_addrs_count = fvec.count; @@ -2555,8 +2555,8 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, fvec->count = 0; } - qsort (addrs, addrs_count, sizeof (struct function_addrs), - function_addrs_compare); + backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), + function_addrs_compare); *ret_addrs = addrs; *ret_addrs_count = addrs_count; @@ -2923,7 +2923,8 @@ build_dwarf_data (struct backtrace_state *state, return NULL; addrs = (struct unit_addrs *) addrs_vec.vec.base; addrs_count = addrs_vec.count; - qsort (addrs, addrs_count, sizeof (struct unit_addrs), unit_addrs_compare); + backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), + unit_addrs_compare); fdata = ((struct dwarf_data *) backtrace_alloc (state, sizeof (struct dwarf_data), diff --git a/src/libbacktrace/elf.c b/src/libbacktrace/elf.c index 5fc74add05..3f14b11a43 100644 --- a/src/libbacktrace/elf.c +++ b/src/libbacktrace/elf.c @@ -1,5 +1,5 @@ /* elf.c -- Get debug data from an ELF file for backtraces. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -407,8 +407,8 @@ elf_initialize_syminfo (struct backtrace_state *state, ++j; } - qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), - elf_symbol_compare); + backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), + elf_symbol_compare); sdata->next = NULL; sdata->symbols = elf_symbols; diff --git a/src/libbacktrace/fileline.c b/src/libbacktrace/fileline.c index f45cccff71..0acad0603e 100644 --- a/src/libbacktrace/fileline.c +++ b/src/libbacktrace/fileline.c @@ -1,5 +1,5 @@ /* fileline.c -- Get file and line number information in a backtrace. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/internal.h b/src/libbacktrace/internal.h index a13c775b62..30f99ca127 100644 --- a/src/libbacktrace/internal.h +++ b/src/libbacktrace/internal.h @@ -1,5 +1,5 @@ /* internal.h -- Internal header file for stack backtrace library. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -99,7 +99,7 @@ extern void backtrace_atomic_store_int (int *, int); /* We have neither the sync nor the atomic functions. These will never be called. */ -#define backtrace_atomic_load_pointer(p) (abort(), 0) +#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) #define backtrace_atomic_load_int(p) (abort(), 0) #define backtrace_atomic_store_pointer(p, v) abort() #define backtrace_atomic_store_size_t(p, v) abort() @@ -196,6 +196,11 @@ extern int backtrace_close (int descriptor, backtrace_error_callback error_callback, void *data); +/* Sort without using memory. */ + +extern void backtrace_qsort (void *base, size_t count, size_t size, + int (*compar) (const void *, const void *)); + /* Allocate memory. This is like malloc. */ extern void *backtrace_alloc (struct backtrace_state *state, size_t size, diff --git a/src/libbacktrace/mmap.c b/src/libbacktrace/mmap.c index 1c691b02e7..1ecf131191 100644 --- a/src/libbacktrace/mmap.c +++ b/src/libbacktrace/mmap.c @@ -1,5 +1,5 @@ /* mmap.c -- Memory allocation with mmap. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. @@ -164,6 +164,26 @@ backtrace_free (struct backtrace_state *state, void *addr, size_t size, { int locked; + /* If we are freeing a large aligned block, just release it back to + the system. This case arises when growing a vector for a large + binary with lots of debug info. Calling munmap here may cause us + to call mmap again if there is also a large shared library; we + just live with that. */ + if (size >= 16 * 4096) + { + size_t pagesize; + + pagesize = getpagesize (); + if (((uintptr_t) addr & (pagesize - 1)) == 0 + && (size & (pagesize - 1)) == 0) + { + /* If munmap fails for some reason, just add the block to + the freelist. */ + if (munmap (addr, size) == 0) + return; + } + } + /* If we can acquire the lock, add the new space to the free list. If we can't acquire the lock, just leak the memory. __sync_lock_test_and_set returns the old state of the lock, so we @@ -209,14 +229,18 @@ backtrace_vector_grow (struct backtrace_state *state,size_t size, alc = pagesize; } else - alc = (alc + pagesize - 1) & ~ (pagesize - 1); + { + alc *= 2; + alc = (alc + pagesize - 1) & ~ (pagesize - 1); + } base = backtrace_alloc (state, alc, error_callback, data); if (base == NULL) return NULL; if (vec->base != NULL) { memcpy (base, vec->base, vec->size); - backtrace_free (state, vec->base, vec->alc, error_callback, data); + backtrace_free (state, vec->base, vec->size + vec->alc, + error_callback, data); } vec->base = base; vec->alc = alc - vec->size; diff --git a/src/libbacktrace/mmapio.c b/src/libbacktrace/mmapio.c index 8b8f124da9..b5a787e0aa 100644 --- a/src/libbacktrace/mmapio.c +++ b/src/libbacktrace/mmapio.c @@ -1,5 +1,5 @@ /* mmapio.c -- File views using mmap. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/nounwind.c b/src/libbacktrace/nounwind.c index f8fdbdc85a..f53f906b5a 100644 --- a/src/libbacktrace/nounwind.c +++ b/src/libbacktrace/nounwind.c @@ -1,5 +1,5 @@ /* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/posix.c b/src/libbacktrace/posix.c index 7f1c35ab97..7fa7cd0d5d 100644 --- a/src/libbacktrace/posix.c +++ b/src/libbacktrace/posix.c @@ -1,5 +1,5 @@ /* posix.c -- POSIX file I/O routines for the backtrace library. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/print.c b/src/libbacktrace/print.c index 70e347f62c..90ecaf89ed 100644 --- a/src/libbacktrace/print.c +++ b/src/libbacktrace/print.c @@ -1,5 +1,5 @@ /* print.c -- Print the current backtrace. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/read.c b/src/libbacktrace/read.c index e373b61de2..299f77ba7c 100644 --- a/src/libbacktrace/read.c +++ b/src/libbacktrace/read.c @@ -1,5 +1,5 @@ /* read.c -- File views without mmap. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/simple.c b/src/libbacktrace/simple.c index dd70f831de..39c2e902ff 100644 --- a/src/libbacktrace/simple.c +++ b/src/libbacktrace/simple.c @@ -1,5 +1,5 @@ /* simple.c -- The backtrace_simple function. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/sort.c b/src/libbacktrace/sort.c new file mode 100644 index 0000000000..bcc765e93a --- /dev/null +++ b/src/libbacktrace/sort.c @@ -0,0 +1,108 @@ +/* sort.c -- Sort without allocating memory + Copyright (C) 2012-2015 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* The GNU glibc version of qsort allocates memory, which we must not + do if we are invoked by a signal handler. So provide our own + sort. */ + +static void +swap (char *a, char *b, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++, a++, b++) + { + char t; + + t = *a; + *a = *b; + *b = t; + } +} + +void +backtrace_qsort (void *basearg, size_t count, size_t size, + int (*compar) (const void *, const void *)) +{ + char *base = (char *) basearg; + size_t i; + size_t mid; + + tail_recurse: + if (count < 2) + return; + + /* The symbol table and DWARF tables, which is all we use this + routine for, tend to be roughly sorted. Pick the middle element + in the array as our pivot point, so that we are more likely to + cut the array in half for each recursion step. */ + swap (base, base + (count / 2) * size, size); + + mid = 0; + for (i = 1; i < count; i++) + { + if ((*compar) (base, base + i * size) > 0) + { + ++mid; + if (i != mid) + swap (base + mid * size, base + i * size, size); + } + } + + if (mid > 0) + swap (base, base + mid * size, size); + + /* Recurse with the smaller array, loop with the larger one. That + ensures that our maximum stack depth is log count. */ + if (2 * mid < count) + { + backtrace_qsort (base, mid, size, compar); + base += (mid + 1) * size; + count -= mid + 1; + goto tail_recurse; + } + else + { + backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), + size, compar); + count = mid; + goto tail_recurse; + } +} diff --git a/src/libbacktrace/state.c b/src/libbacktrace/state.c index bef47bd1a0..a846378e90 100644 --- a/src/libbacktrace/state.c +++ b/src/libbacktrace/state.c @@ -1,5 +1,5 @@ /* state.c -- Create the backtrace state. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libbacktrace/stest.c b/src/libbacktrace/stest.c new file mode 100644 index 0000000000..ec93e680e8 --- /dev/null +++ b/src/libbacktrace/stest.c @@ -0,0 +1,137 @@ +/* stest.c -- Test for libbacktrace internal sort function + Copyright (C) 2012-2015 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Test the local qsort implementation. */ + +#define MAX 10 + +struct test +{ + size_t count; + int input[MAX]; + int output[MAX]; +}; + +static struct test tests[] = + { + { + 10, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + }, + { + 9, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }, + { + 10, + { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 9, + { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + }, + { + 10, + { 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 5, + { 4, 5, 3, 1, 2 }, + { 1, 2, 3, 4, 5 }, + }, + { + 5, + { 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1 }, + }, + { + 5, + { 1, 1, 2, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + { + 5, + { 2, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + }; + +static int +compare (const void *a, const void *b) +{ + const int *ai = (const int *) a; + const int *bi = (const int *) b; + + return *ai - *bi; +} + +int +main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + int failures; + size_t i; + int a[MAX]; + + failures = 0; + for (i = 0; i < sizeof tests / sizeof tests[0]; i++) + { + memcpy (a, tests[i].input, tests[i].count * sizeof (int)); + backtrace_qsort (a, tests[i].count, sizeof (int), compare); + if (memcmp (a, tests[i].output, tests[i].count * sizeof (int)) != 0) + { + size_t j; + + fprintf (stderr, "test %d failed:", (int) i); + for (j = 0; j < tests[i].count; j++) + fprintf (stderr, " %d", a[j]); + fprintf (stderr, "\n"); + ++failures; + } + } + + exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/src/libbacktrace/unknown.c b/src/libbacktrace/unknown.c index e5e8421b3a..e89cba96f7 100644 --- a/src/libbacktrace/unknown.c +++ b/src/libbacktrace/unknown.c @@ -1,5 +1,5 @@ /* unknown.c -- used when backtrace configury does not know file format. - Copyright (C) 2012-2014 Free Software Foundation, Inc. + Copyright (C) 2012-2015 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. Redistribution and use in source and binary forms, with or without @@ -7,13 +7,13 @@ modification, are permitted provided that the following conditions are met: (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. + notice, this list of conditions and the following disclaimer. (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the - distribution. - + distribution. + (3) The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 3804874a65..0f05e5796a 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -152,8 +152,7 @@ use core::prelude::*; -use core::default::Default; -use core::iter::{FromIterator, IntoIterator}; +use core::iter::{FromIterator}; use core::mem::{zeroed, replace, swap}; use core::ptr; @@ -250,28 +249,6 @@ impl BinaryHeap { Iter { iter: self.data.iter() } } - /// Creates a consuming iterator, that is, one that moves each value out of - /// the binary heap in arbitrary order. The binary heap cannot be used - /// after calling this. - /// - /// # Examples - /// - /// ``` - /// # #![feature(collections)] - /// use std::collections::BinaryHeap; - /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); - /// - /// // Print 1, 2, 3, 4 in arbitrary order - /// for x in heap.into_iter() { - /// // x has type i32, not &i32 - /// println!("{}", x); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - IntoIter { iter: self.data.into_iter() } - } - /// Returns the greatest item in the binary heap, or `None` if it is empty. /// /// # Examples @@ -675,8 +652,25 @@ impl IntoIterator for BinaryHeap { type Item = T; type IntoIter = IntoIter; + /// Creates a consuming iterator, that is, one that moves each value out of + /// the binary heap in arbitrary order. The binary heap cannot be used + /// after calling this. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections)] + /// use std::collections::BinaryHeap; + /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]); + /// + /// // Print 1, 2, 3, 4 in arbitrary order + /// for x in heap.into_iter() { + /// // x has type i32, not &i32 + /// println!("{}", x); + /// } + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + IntoIter { iter: self.data.into_iter() } } } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 8874ac6eb8..d9151298a3 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -40,7 +40,6 @@ //! ``` //! # #![feature(collections, core, step_by)] //! use std::collections::{BitSet, BitVec}; -//! use std::num::Float; //! use std::iter; //! //! let max_prime = 10000; @@ -85,12 +84,11 @@ use core::prelude::*; use core::cmp::Ordering; use core::cmp; -use core::default::Default; use core::fmt; use core::hash; use core::iter::RandomAccessIterator; use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned}; -use core::iter::{self, FromIterator, IntoIterator}; +use core::iter::{self, FromIterator}; use core::ops::Index; use core::slice; use core::{u8, u32, usize}; @@ -190,17 +188,17 @@ fn blocks_for_bits(bits: usize) -> usize { // // Note that we can technically avoid this branch with the expression // `(nbits + u32::BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow. - if bits % u32::BITS as usize == 0 { - bits / u32::BITS as usize + if bits % u32::BITS == 0 { + bits / u32::BITS } else { - bits / u32::BITS as usize + 1 + bits / u32::BITS + 1 } } /// Computes the bitmask for the final word of the vector fn mask_for_bits(bits: usize) -> u32 { // Note especially that a perfect multiple of u32::BITS should mask all 1s. - !0 >> (u32::BITS as usize - bits % u32::BITS as usize) % u32::BITS as usize + !0 >> (u32::BITS - bits % u32::BITS) % u32::BITS } impl BitVec { @@ -238,7 +236,7 @@ impl BitVec { /// An operation might screw up the unused bits in the last block of the /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up. fn fix_last_block(&mut self) { - let extra_bits = self.len() % u32::BITS as usize; + let extra_bits = self.len() % u32::BITS; if extra_bits > 0 { let mask = (1 << extra_bits) - 1; let storage_len = self.storage.len(); @@ -317,7 +315,7 @@ impl BitVec { /// false, false, true, false])); /// ``` pub fn from_bytes(bytes: &[u8]) -> BitVec { - let len = bytes.len().checked_mul(u8::BITS as usize).expect("capacity overflow"); + let len = bytes.len().checked_mul(u8::BITS).expect("capacity overflow"); let mut bit_vec = BitVec::with_capacity(len); let complete_words = bytes.len() / 4; let extra_bytes = bytes.len() % 4; @@ -386,8 +384,8 @@ impl BitVec { if i >= self.nbits { return None; } - let w = i / u32::BITS as usize; - let b = i % u32::BITS as usize; + let w = i / u32::BITS; + let b = i % u32::BITS; self.storage.get(w).map(|&block| (block & (1 << b)) != 0 ) @@ -414,8 +412,8 @@ impl BitVec { reason = "panic semantics are likely to change in the future")] pub fn set(&mut self, i: usize, x: bool) { assert!(i < self.nbits); - let w = i / u32::BITS as usize; - let b = i % u32::BITS as usize; + let w = i / u32::BITS; + let b = i % u32::BITS; let flag = 1 << b; let val = if x { self.storage[w] | flag } else { self.storage[w] & !flag }; @@ -811,7 +809,7 @@ impl BitVec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.storage.capacity().checked_mul(u32::BITS as usize).unwrap_or(usize::MAX) + self.storage.capacity().checked_mul(u32::BITS).unwrap_or(usize::MAX) } /// Grows the `BitVec` in-place, adding `n` copies of `value` to the `BitVec`. @@ -842,7 +840,7 @@ impl BitVec { // Correct the old tail word, setting or clearing formerly unused bits let num_cur_blocks = blocks_for_bits(self.nbits); - if self.nbits % u32::BITS as usize > 0 { + if self.nbits % u32::BITS > 0 { let mask = mask_for_bits(self.nbits); if value { self.storage[num_cur_blocks - 1] |= !mask; @@ -892,7 +890,7 @@ impl BitVec { // (3) self.set(i, false); self.nbits = i; - if self.nbits % u32::BITS as usize == 0 { + if self.nbits % u32::BITS == 0 { // (2) self.storage.pop(); } @@ -915,7 +913,7 @@ impl BitVec { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, elem: bool) { - if self.nbits % u32::BITS as usize == 0 { + if self.nbits % u32::BITS == 0 { self.storage.push(0); } let insert_pos = self.nbits; @@ -923,7 +921,7 @@ impl BitVec { self.set(insert_pos, elem); } - /// Return the total number of bits in this vector + /// Returns the total number of bits in this vector #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.nbits } @@ -1433,7 +1431,7 @@ impl BitSet { // Truncate let trunc_len = cmp::max(old_len - n, 1); bit_vec.storage.truncate(trunc_len); - bit_vec.nbits = trunc_len * u32::BITS as usize; + bit_vec.nbits = trunc_len * u32::BITS; } /// Iterator over each u32 stored in the `BitSet`. @@ -1695,7 +1693,7 @@ impl BitSet { self.other_op(other, |w1, w2| w1 ^ w2); } - /// Return the number of set bits in this set. + /// Returns the number of set bits in this set. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { @@ -1871,13 +1869,13 @@ impl<'a> Iterator for TwoBitPositions<'a> { fn next(&mut self) -> Option { while self.next_idx < self.set.bit_vec.len() || self.next_idx < self.other.bit_vec.len() { - let bit_idx = self.next_idx % u32::BITS as usize; + let bit_idx = self.next_idx % u32::BITS; if bit_idx == 0 { let s_bit_vec = &self.set.bit_vec; let o_bit_vec = &self.other.bit_vec; // Merging the two words is a bit of an awkward dance since // one BitVec might be longer than the other - let word_idx = self.next_idx / u32::BITS as usize; + let word_idx = self.next_idx / u32::BITS; let w1 = if word_idx < s_bit_vec.storage.len() { s_bit_vec.storage[word_idx] } else { 0 }; diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 2fe769b73f..7332bf4670 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -39,7 +39,7 @@ use self::Cow::*; /// Borrow>` and `Vec: Borrow<[T]>`. #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { - /// Immutably borrow from an owned value. + /// Immutably borrows from an owned value. /// /// # Examples /// @@ -67,7 +67,7 @@ pub trait Borrow { /// Similar to `Borrow`, but for mutable borrows. #[stable(feature = "rust1", since = "1.0.0")] pub trait BorrowMut : Borrow { - /// Mutably borrow from an owned value. + /// Mutably borrows from an owned value. /// /// # Examples /// @@ -126,7 +126,7 @@ impl<'a, B: ?Sized> Borrow for Cow<'a, B> where B: ToOwned, ::O } } -/// A generalization of Clone to borrowed data. +/// A generalization of `Clone` to borrowed data. /// /// Some types make it possible to go from borrowed to owned, usually by /// implementing the `Clone` trait. But `Clone` works only for going from `&T` @@ -137,7 +137,7 @@ pub trait ToOwned { #[stable(feature = "rust1", since = "1.0.0")] type Owned: Borrow; - /// Create owned data from borrowed data, usually by copying. + /// Creates owned data from borrowed data, usually by cloning. #[stable(feature = "rust1", since = "1.0.0")] fn to_owned(&self) -> Self::Owned; } @@ -155,9 +155,9 @@ impl ToOwned for T where T: Clone { /// data lazily when mutation or ownership is required. The type is designed to /// work with general borrowed data via the `Borrow` trait. /// -/// `Cow` implements both `Deref`, which means that you can call +/// `Cow` implements `Deref`, which means that you can call /// non-mutating methods directly on the data it encloses. If mutation -/// is desired, `to_mut` will obtain a mutable references to an owned +/// is desired, `to_mut` will obtain a mutable reference to an owned /// value, cloning if necessary. /// /// # Examples @@ -200,7 +200,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned { } impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { - /// Acquire a mutable reference to the owned form of the data. + /// Acquires a mutable reference to the owned form of the data. /// /// Copies the data if it is not already owned. /// @@ -226,7 +226,7 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned { } } - /// Extract the owned data. + /// Extracts the owned data. /// /// Copies the data if it is not already owned. /// @@ -327,7 +327,7 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned } } -/// Trait for moving into a `Cow` +/// Trait for moving into a `Cow`. #[unstable(feature = "into_cow", reason = "may be replaced by `convert::Into`")] pub trait IntoCow<'a, B: ?Sized> where B: ToOwned { /// Moves `self` into `Cow` @@ -342,7 +342,7 @@ impl<'a, B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Clone> AsRef for Cow<'a, T> { +impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { fn as_ref(&self) -> &T { self } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index adfb284dab..291b66939e 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -20,10 +20,9 @@ use self::Entry::*; use core::prelude::*; use core::cmp::Ordering; -use core::default::Default; use core::fmt::Debug; use core::hash::{Hash, Hasher}; -use core::iter::{Map, FromIterator, IntoIterator}; +use core::iter::{Map, FromIterator}; use core::ops::Index; use core::{iter, fmt, mem, usize}; use Bound::{self, Included, Excluded, Unbounded}; @@ -261,9 +260,8 @@ impl BTreeMap { /// /// let mut map = BTreeMap::new(); /// map.insert(1, "a"); - /// match map.get_mut(&1) { - /// Some(x) => *x = "b", - /// None => (), + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; /// } /// assert_eq!(map[&1], "b"); /// ``` @@ -313,7 +311,7 @@ impl BTreeMap { // 2) While ODS may potentially return the pair we *just* inserted after // the split, we will never do this. Again, this shouldn't effect the analysis. - /// Inserts a key-value pair from the map. If the key already had a value + /// Inserts a key-value pair into the map. If the key already had a value /// present in the map, that value is returned. Otherwise, `None` is returned. /// /// # Examples @@ -472,8 +470,32 @@ impl IntoIterator for BTreeMap { type Item = (K, V); type IntoIter = IntoIter; + /// Gets an owning iterator over the entries of the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map = BTreeMap::new(); + /// map.insert(1, "a"); + /// map.insert(2, "b"); + /// map.insert(3, "c"); + /// + /// for (key, value) in map.into_iter() { + /// println!("{}: {}", key, value); + /// } + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + let len = self.len(); + let mut lca = VecDeque::new(); + lca.push_back(Traverse::traverse(self.root)); + IntoIter { + inner: AbsIter { + traversals: lca, + size: len, + } + } } } @@ -692,7 +714,7 @@ mod stack { // We've reached the root, so no matter what, we're done. We manually // access the root via the tree itself to avoid creating any dangling // pointers. - if self.map.root.len() == 0 && !self.map.root.is_leaf() { + if self.map.root.is_empty() && !self.map.root.is_leaf() { // We've emptied out the root, so make its only child the new root. // If it's a leaf, we just let it become empty. self.map.depth -= 1; @@ -1264,35 +1286,6 @@ impl BTreeMap { } } - /// Gets an owning iterator over the entries of the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map = BTreeMap::new(); - /// map.insert(1, "a"); - /// map.insert(2, "b"); - /// map.insert(3, "c"); - /// - /// for (key, value) in map.into_iter() { - /// println!("{}: {}", key, value); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - let len = self.len(); - let mut lca = VecDeque::new(); - lca.push_back(Traverse::traverse(self.root)); - IntoIter { - inner: AbsIter { - traversals: lca, - size: len, - } - } - } - /// Gets an iterator over the keys of the map. /// /// # Examples @@ -1339,7 +1332,7 @@ impl BTreeMap { Values { inner: self.iter().map(second) } } - /// Return the number of elements in the map. + /// Returns the number of elements in the map. /// /// # Examples /// @@ -1354,7 +1347,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.length } - /// Return true if the map contains no elements. + /// Returns true if the map contains no elements. /// /// # Examples /// diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 26c5725604..a480335c94 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -585,6 +585,9 @@ impl Node { self._len } + /// Does the node not contain any key-value pairs + pub fn is_empty(&self) -> bool { self.len() == 0 } + /// How many key-value pairs the node can fit pub fn capacity(&self) -> usize { self._capacity @@ -1097,7 +1100,7 @@ impl Node { /// When a node has no keys or values and only a single edge, extract that edge. pub fn hoist_lone_child(&mut self) { // Necessary for correctness, but in a private module - debug_assert!(self.len() == 0); + debug_assert!(self.is_empty()); debug_assert!(!self.is_leaf()); unsafe { @@ -1225,7 +1228,7 @@ impl Node { /// because we have one too many, and our parent now has one too few fn split(&mut self) -> (K, V, Node) { // Necessary for correctness, but in a private function - debug_assert!(self.len() > 0); + debug_assert!(!self.is_empty()); let mut right = if self.is_leaf() { Node::new_leaf(self.capacity()) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 840110b5b2..fc346151e0 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -14,10 +14,9 @@ use core::prelude::*; use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::default::Default; use core::fmt::Debug; use core::fmt; -use core::iter::{Peekable, Map, FromIterator, IntoIterator}; +use core::iter::{Peekable, Map, FromIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub}; use borrow::Borrow; @@ -132,27 +131,6 @@ impl BTreeSet { pub fn iter(&self) -> Iter { Iter { iter: self.map.keys() } } - - /// Gets an iterator for moving out the BtreeSet's contents. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::collections::BTreeSet; - /// - /// let set: BTreeSet = [1, 2, 3, 4].iter().cloned().collect(); - /// - /// let v: Vec = set.into_iter().collect(); - /// assert_eq!(v, [1, 2, 3, 4]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - fn first((a, _): (A, B)) -> A { a } - let first: fn((T, ())) -> T = first; // coerce to fn pointer - - IntoIter { iter: self.map.into_iter().map(first) } - } } impl BTreeSet { @@ -284,7 +262,7 @@ impl BTreeSet { Union{a: self.iter().peekable(), b: other.iter().peekable()} } - /// Return the number of elements in the set + /// Returns the number of elements in the set. /// /// # Examples /// @@ -299,7 +277,7 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.map.len() } - /// Returns true if the set contains no elements + /// Returns true if the set contains no elements. /// /// # Examples /// @@ -500,8 +478,24 @@ impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; + /// Gets an iterator for moving out the BtreeSet's contents. + /// + /// # Examples + /// + /// ``` + /// # #![feature(core)] + /// use std::collections::BTreeSet; + /// + /// let set: BTreeSet = [1, 2, 3, 4].iter().cloned().collect(); + /// + /// let v: Vec = set.into_iter().collect(); + /// assert_eq!(v, [1, 2, 3, 4]); + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + fn first((a, _): (A, B)) -> A { a } + let first: fn((T, ())) -> T = first; // coerce to fn pointer + + IntoIter { iter: self.map.into_iter().map(first) } } } diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 0b206d381d..e6cdb88d3e 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -16,7 +16,7 @@ use core::prelude::*; use core::marker; use core::fmt; -use core::iter::{FromIterator, IntoIterator}; +use core::iter::{FromIterator}; use core::ops::{Sub, BitOr, BitAnd, BitXor}; // FIXME(contentions): implement union family of methods? (general design may be wrong here) @@ -86,7 +86,7 @@ pub trait CLike { fn bit(e: &E) -> usize { use core::usize; let value = e.to_usize(); - assert!(value < usize::BITS as usize, + assert!(value < usize::BITS, "EnumSet only supports up to {} variants.", usize::BITS - 1); 1 << value } diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 46b1ad2138..1dac90dc34 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -177,7 +177,6 @@ //! # #![feature(core, std_misc)] //! use std::fmt; //! use std::f64; -//! use std::num::Float; //! //! #[derive(Debug)] //! struct Vector2D { @@ -202,10 +201,11 @@ //! let magnitude = magnitude.sqrt(); //! //! // Respect the formatting flags by using the helper method -//! // `pad_integral` on the Formatter object. See the method documentation -//! // for details, and the function `pad` can be used to pad strings. +//! // `pad_integral` on the Formatter object. See the method +//! // documentation for details, and the function `pad` can be used +//! // to pad strings. //! let decimals = f.precision().unwrap_or(3); -//! let string = f64::to_str_exact(magnitude, decimals); +//! let string = format!("{:.*}", decimals, magnitude); //! f.pad_integral(true, "", &string) //! } //! } @@ -246,7 +246,7 @@ //! //! ```ignore //! format! // described above -//! write! // first argument is a &mut old_io::Writer, the destination +//! write! // first argument is a &mut io::Write, the destination //! writeln! // same as write but appends a newline //! print! // the format string is printed to the standard output //! println! // same as print but appends a newline @@ -398,14 +398,71 @@ //! //! ## Precision //! -//! For non-numeric types, this can be considered a "maximum width". If the -//! resulting string is longer than this width, then it is truncated down to -//! this many characters and only those are emitted. +//! For non-numeric types, this can be considered a "maximum width". If the resulting string is +//! longer than this width, then it is truncated down to this many characters and only those are +//! emitted. //! //! For integral types, this has no meaning currently. //! -//! For floating-point types, this indicates how many digits after the decimal -//! point should be printed. +//! For floating-point types, this indicates how many digits after the decimal point should be +//! printed. +//! +//! 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 `.*`. +//! +//! The first specification, `.N`, means the integer `N` itself is the precision. +//! +//! The second, `.N$`, means use format *argument* `N` (which must be a `usize`) as the precision. +//! +//! 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 ``. +//! +//! For example, these: +//! +//! ``` +//! // Hello {arg 0 (x)} is {arg 1 (0.01} with precision specified inline (5)} +//! println!("Hello {0} is {1:.5}", "x", 0.01); +//! +//! // Hello {arg 1 (x)} is {arg 2 (0.01} with precision specified in arg 0 (5)} +//! println!("Hello {1} is {2:.0$}", 5, "x", 0.01); +//! +//! // Hello {arg 0 (x)} is {arg 2 (0.01} with precision specified in arg 1 (5)} +//! println!("Hello {0} is {2:.1$}", "x", 5, 0.01); +//! +//! // Hello {next arg (x)} is {second of next two args (0.01} with precision +//! // specified in first of next two args (5)} +//! println!("Hello {} is {:.*}", "x", 5, 0.01); +//! +//! // Hello {next arg (x)} is {arg 2 (0.01} with precision +//! // specified in its predecessor (5)} +//! println!("Hello {} is {2:.*}", "x", 5, 0.01); +//! ``` +//! +//! All print the same thing: +//! +//! ```text +//! Hello x is 0.01000 +//! ``` +//! +//! While these: +//! +//! ``` +//! println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56); +//! println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56"); +//! ``` +//! +//! print two significantly different things: +//! +//! ```text +//! Hello, `1234.560` has 3 fractional digits +//! Hello, `123` has 3 characters +//! ``` //! //! # Escaping //! diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 7658611d80..9462f7a2d9 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -38,8 +38,10 @@ #![feature(unsafe_no_drop_flag, filling_drop)] #![feature(step_by)] #![feature(str_char)] +#![feature(str_words)] #![feature(slice_patterns)] #![feature(debug_builders)] +#![feature(utf8_error)] #![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))] #![cfg_attr(test, allow(deprecated))] // rand diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index dbdb795657..deb1476c23 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -25,10 +25,9 @@ use core::prelude::*; use alloc::boxed::Box; use core::cmp::Ordering; -use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; -use core::iter::{self, FromIterator, IntoIterator}; +use core::iter::{self, FromIterator}; use core::mem; use core::ptr; @@ -296,13 +295,6 @@ impl LinkedList { } } - /// Consumes the list into an iterator yielding elements by value. - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - IntoIter{list: self} - } - /// Returns `true` if the `LinkedList` is empty. /// /// This operation should compute in O(1) time. @@ -852,8 +844,10 @@ impl IntoIterator for LinkedList { type Item = T; type IntoIter = IntoIter; + /// Consumes the list into an iterator yielding elements by value. + #[inline] fn into_iter(self) -> IntoIter { - self.into_iter() + IntoIter{list: self} } } @@ -941,9 +935,9 @@ impl Hash for LinkedList { #[cfg(test)] mod test { use std::clone::Clone; - use std::iter::Iterator; + use std::iter::{Iterator, IntoIterator}; use std::option::Option::{Some, None, self}; - use std::rand; + use std::__rand::{thread_rng, Rng}; use std::thread; use std::vec::Vec; @@ -1095,7 +1089,7 @@ mod test { let mut v = vec![]; for i in 0..sz { check_links(&m); - let r: u8 = rand::random(); + let r: u8 = thread_rng().next_u32() as u8; match r % 6 { 0 => { m.pop_back(); diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ff923fb190..6622d8a9c4 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -85,7 +85,6 @@ use core::clone::Clone; use core::cmp::Ordering::{self, Greater, Less}; use core::cmp::{self, Ord, PartialEq}; use core::iter::Iterator; -use core::iter::MultiplicativeIterator; use core::marker::Sized; use core::mem::size_of; use core::mem; @@ -99,7 +98,7 @@ use self::Direction::*; use borrow::{Borrow, BorrowMut, ToOwned}; use vec::Vec; -pub use core::slice::{Chunks, AsSlice, Windows}; +pub use core::slice::{Chunks, Windows}; pub use core::slice::{Iter, IterMut}; pub use core::slice::{IntSliceExt, SplitMut, ChunksMut, Split}; pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; @@ -550,7 +549,7 @@ impl [T] { core_slice::SliceExt::binary_search_by(self, f) } - /// Return the number of elements in the slice + /// Returns the number of elements in the slice. /// /// # Example /// @@ -758,7 +757,7 @@ impl [T] { core_slice::SliceExt::get_unchecked_mut(self, index) } - /// Return an unsafe mutable pointer to the slice's buffer. + /// Returns an unsafe mutable pointer to the slice's buffer. /// /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. @@ -985,7 +984,7 @@ impl [T] { core_slice::SliceExt::ends_with(self, needle) } - /// Convert `self` into a vector without clones or allocation. + /// Converts `self` into a vector without clones or allocation. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn into_vec(self: Box) -> Vec { @@ -1182,7 +1181,7 @@ impl Iterator for ElementSwaps { #[inline] fn size_hint(&self) -> (usize, Option) { // For a vector of size n, there are exactly n! permutations. - let n = (2..self.sdir.len() + 1).product(); + let n: usize = (2..self.sdir.len() + 1).product(); (n - self.swaps_made, Some(n - self.swaps_made)) } } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index c22b6fb928..7a28b56b7c 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -53,11 +53,12 @@ use self::RecompositionState::*; use self::DecompositionType::*; use core::clone::Clone; -use core::iter::AdditiveIterator; use core::iter::{Iterator, Extend}; use core::option::Option::{self, Some, None}; use core::result::Result; use core::str as core_str; +use core::str::pattern::Pattern; +use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use unicode::str::{UnicodeStr, Utf16Encoder}; use core::convert::AsRef; @@ -68,15 +69,17 @@ use unicode; use vec::Vec; use slice::SliceConcatExt; -pub use core::str::{FromStr, Utf8Error, Str}; -pub use core::str::{Lines, LinesAny, MatchIndices, CharRange}; -pub use core::str::{Split, SplitTerminator, SplitN}; -pub use core::str::{RSplit, RSplitN}; +pub use core::str::{FromStr, Utf8Error}; +pub use core::str::{Lines, LinesAny, CharRange}; +pub use core::str::{Split, RSplit}; +pub use core::str::{SplitN, RSplitN}; +pub use core::str::{SplitTerminator, RSplitTerminator}; +pub use core::str::{Matches, RMatches}; +pub use core::str::{MatchIndices, RMatchIndices}; pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; pub use core::str::{from_utf8_unchecked, ParseBoolError}; pub use unicode::str::{Words, Graphemes, GraphemeIndices}; -pub use core::str::Pattern; -pub use core::str::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep}; +pub use core::str::pattern; /* Section: Creating a string @@ -112,7 +115,7 @@ impl> SliceConcatExt for [S] { // this is wrong without the guarantee that `self` is non-empty // `len` calculation may overflow but push_str but will check boundaries let len = sep.len() * (self.len() - 1) - + self.iter().map(|s| s.as_ref().len()).sum(); + + self.iter().map(|s| s.as_ref().len()).sum::(); let mut result = String::with_capacity(len); let mut first = true; @@ -429,7 +432,8 @@ impl str { /// Replaces all occurrences of one string with another. /// - /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a second `&str` to + /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a + /// second `&str` to /// replace it with. If the original `&str` isn't found, no change occurs. /// /// # Examples @@ -581,12 +585,24 @@ impl str { /// An iterator over substrings of `self`, separated by characters /// matched by a pattern. /// - /// The pattern can be a simple `&str`, or a closure that determines - /// the split. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator will be double ended if the pattern allows a + /// reverse search and forward/reverse search yields the same elements. + /// This is true for, eg, `char` but not + /// for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, `rsplit()` can be used. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); @@ -594,81 +610,116 @@ impl str { /// /// let v: Vec<&str> = "".split('X').collect(); /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); + /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["abc", "def", "ghi"]); /// - /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); - /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); + /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { core_str::StrExt::split(&self[..], pat) } - /// An iterator over substrings of `self`, separated by characters matched - /// by a pattern, returning most `count` items. + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. /// - /// The pattern can be a simple `&str`, or a closure that determines - /// the split. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. /// - /// The last element returned, if any, will contain the remainder of the - /// string. + /// # Iterator behavior /// - /// # Examples + /// The returned iterator requires that the pattern supports a + /// reverse search, + /// and it will be double ended if a forward/reverse search yields + /// the same elements. /// - /// Simple `&str` patterns: + /// For iterating from the front, `split()` can be used. /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect(); - /// assert_eq!(v, ["Mary", "had a little lambda"]); + /// # Examples /// - /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect(); - /// assert_eq!(v, ["lion", "XtigerXleopard"]); + /// Simple patterns: /// - /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); - /// assert_eq!(v, ["abcXdef"]); + /// ```rust + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); /// - /// let v: Vec<&str> = "".splitn(1, 'X').collect(); + /// let v: Vec<&str> = "".rsplit('X').collect(); /// assert_eq!(v, [""]); - /// ``` /// - /// More complex patterns with a lambda: + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); /// ``` - /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect(); - /// assert_eq!(v, ["abc", "def2ghi"]); + /// + /// More complex patterns with closures: + /// + /// ```rust + /// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// + /// let v: Vec<&str> = "lionXtigerXleopard".rsplit(char::is_uppercase).collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { - core_str::StrExt::splitn(&self[..], count, pat) + pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rsplit(&self[..], pat) } /// An iterator over substrings of `self`, separated by characters /// matched by a pattern. /// - /// Equivalent to `split`, except that the trailing substring is skipped if empty. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns + /// like regular expressions. /// - /// The pattern can be a simple `&str`, or a closure that determines - /// the split. + /// Equivalent to `split`, except that the trailing substring + /// is skipped if empty. + /// + /// This method can be used for string data that is _terminated_, + /// rather than _seperated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be double ended if the pattern allows a + /// reverse search + /// and forward/reverse search yields the same elements. This is true + /// for, eg, `char` but not for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, `rsplit_terminator()` can be used. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); /// assert_eq!(v, ["A", "B"]); /// - /// let v: Vec<&str> = "A..B..".split_terminator('.').collect(); + /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); /// assert_eq!(v, ["A", "", "B", ""]); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// let v: Vec<&str> = "abc1def2ghi3".split_terminator(|c: char| c.is_numeric()).collect(); @@ -679,32 +730,98 @@ impl str { core_str::StrExt::split_terminator(&self[..], pat) } - /// An iterator over substrings of `self`, separated by a pattern, - /// starting from the end of the string. + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// Equivalent to `split`, except that the trailing substring is + /// skipped if empty. + /// + /// This method can be used for string data that is _terminated_, + /// rather than _seperated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, `split_terminator()` can be used. /// /// # Examples /// /// Simple patterns: /// /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); + /// assert_eq!(v, ["B", "A"]); /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); + /// assert_eq!(v, ["", "B", "", "A"]); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` - /// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect(); + /// let v: Vec<&str> = "abc1def2ghi3".rsplit_terminator(|c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["ghi", "def", "abc"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P::Searcher: ReverseSearcher<'a> { - core_str::StrExt::rsplit(&self[..], pat) + core_str::StrExt::rsplit_terminator(&self[..], pat) + } + + /// An iterator over substrings of `self`, separated by a pattern, + /// restricted to returning + /// at most `count` items. + /// + /// The last element returned, if any, will contain the remainder of the + /// string. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, `rsplitn()` can be used. + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); + /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn(1, 'X').collect(); + /// assert_eq!(v, [""]); + /// ``` + /// + /// More complex patterns with closures: + /// + /// ``` + /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect(); + /// assert_eq!(v, ["abc", "def2ghi"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { + core_str::StrExt::splitn(&self[..], count, pat) } /// An iterator over substrings of `self`, separated by a pattern, @@ -714,6 +831,18 @@ impl str { /// The last element returned, if any, will contain the remainder of the /// string. /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// `splitn()` can be used for splitting from the front. + /// /// # Examples /// /// Simple patterns: @@ -722,11 +851,14 @@ impl str { /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); /// assert_eq!(v, ["lamb", "little", "Mary had a"]); /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "lionX"]); + /// /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); /// assert_eq!(v, ["leopard", "lion::tiger"]); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect(); @@ -739,34 +871,166 @@ impl str { core_str::StrExt::rsplitn(&self[..], count, pat) } - /// An iterator over the start and end indices of the disjoint matches of a `&str` within - /// `self`. + /// An iterator over the matches of a pattern within `self`. + /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator will be double ended if the pattern allows + /// a reverse search + /// and forward/reverse search yields the same elements. This is true + /// for, eg, `char` but not + /// for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, `rmatches()` can be used. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections)] + /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".matches(|c: char| c.is_numeric()).collect(); + /// assert_eq!(v, ["1", "2", "3"]); + /// ``` + #[unstable(feature = "collections", + reason = "method got recently added")] + pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + core_str::StrExt::matches(&self[..], pat) + } + + /// An iterator over the matches of a pattern within `self`, yielded in + /// reverse order. + /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, + /// and it will be double ended if a forward/reverse search yields + /// the same elements. + /// + /// For iterating from the front, `matches()` can be used. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections)] + /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".rmatches(|c: char| c.is_numeric()).collect(); + /// assert_eq!(v, ["3", "2", "1"]); + /// ``` + #[unstable(feature = "collections", + reason = "method got recently added")] + pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rmatches(&self[..], pat) + } + + /// An iterator over the start and end indices of the disjoint matches + /// of a pattern within `self`. /// - /// That is, each returned value `(start, end)` satisfies `self.slice(start, end) == sep`. For - /// matches of `sep` within `self` that overlap, only the indices corresponding to the first + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the first /// match are returned. /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines + /// the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator will be double ended if the pattern allows a + /// reverse search + /// and forward/reverse search yields the same elements. This is true for, + /// eg, `char` but not + /// for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, `rmatch_indices()` can be used. + /// /// # Examples /// /// ``` /// # #![feature(collections)] /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect(); - /// assert_eq!(v, [(0,3), (6,9), (12,15)]); + /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]); /// /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect(); - /// assert_eq!(v, [(1,4), (4,7)]); + /// assert_eq!(v, [(1, 4), (4, 7)]); /// /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect(); /// assert_eq!(v, [(0, 3)]); // only the first `aba` /// ``` #[unstable(feature = "collections", reason = "might have its iterator type changed")] - // NB: Right now MatchIndices yields `(usize, usize)`, - // but it would be more consistent and useful to return `(usize, &str)` + // NB: Right now MatchIndices yields `(usize, usize)`, but it would + // be more consistent with `matches` and `char_indices` to return `(usize, &str)` pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { core_str::StrExt::match_indices(&self[..], pat) } + /// An iterator over the start and end indices of the disjoint matches of + /// a pattern within + /// `self`, yielded in reverse order. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the last + /// match are returned. + /// + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines + /// the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, + /// and it will be double ended if a forward/reverse search yields + /// the same elements. + /// + /// For iterating from the front, `match_indices()` can be used. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections)] + /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]); + /// + /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(4, 7), (1, 4)]); + /// + /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect(); + /// assert_eq!(v, [(2, 5)]); // only the last `aba` + /// ``` + #[unstable(feature = "collections", + reason = "might have its iterator type changed")] + // NB: Right now RMatchIndices yields `(usize, usize)`, but it would + // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)` + pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rmatch_indices(&self[..], pat) + } + /// An iterator over the lines of a string, separated by `\n`. /// /// This does not include the empty string after a trailing `\n`. @@ -793,7 +1057,8 @@ impl str { core_str::StrExt::lines(&self[..]) } - /// An iterator over the lines of a string, separated by either `\n` or `\r\n`. + /// An iterator over the lines of a string, separated by either + /// `\n` or `\r\n`. /// /// As with `.lines()`, this does not include an empty trailing line. /// @@ -855,7 +1120,8 @@ impl str { /// /// # Unsafety /// - /// Caller must check both UTF-8 character boundaries and the boundaries of the entire slice as + /// Caller must check both UTF-8 character boundaries and the boundaries + /// of the entire slice as /// well. /// /// # Examples @@ -898,13 +1164,15 @@ impl str { core_str::StrExt::ends_with(&self[..], pat) } - /// Returns a string with all pre- and suffixes that match a pattern repeatedly removed. + /// Returns a string with all pre- and suffixes that match a pattern + /// repeatedly removed. /// - /// The pattern can be a simple `&str`, or a closure that determines the split. + /// The pattern can be a simple `char`, or a closure that determines + /// the split. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); @@ -913,7 +1181,7 @@ impl str { /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar"); @@ -925,13 +1193,15 @@ impl str { core_str::StrExt::trim_matches(&self[..], pat) } - /// Returns a string with all prefixes that match a pattern repeatedly removed. + /// Returns a string with all prefixes that match a pattern + /// repeatedly removed. /// - /// The pattern can be a simple `&str`, or a closure that determines the split. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); @@ -940,7 +1210,7 @@ impl str { /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123"); @@ -950,13 +1220,15 @@ impl str { core_str::StrExt::trim_left_matches(&self[..], pat) } - /// Returns a string with all suffixes that match a pattern repeatedly removed. + /// Returns a string with all suffixes that match a pattern + /// repeatedly removed. /// - /// The pattern can be a simple `&str`, or a closure that determines the split. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the split. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); @@ -964,7 +1236,7 @@ impl str { /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar"); @@ -976,9 +1248,11 @@ impl str { core_str::StrExt::trim_right_matches(&self[..], pat) } - /// Check that `index`-th byte lies at the start and/or end of a UTF-8 code point sequence. + /// Checks that `index`-th byte lies at the start and/or end of a + /// UTF-8 code point sequence. /// - /// The start and end of the string (when `index == self.len()`) are considered to be + /// The start and end of the string (when `index == self.len()`) are + /// considered to be /// boundaries. /// /// # Panics @@ -1021,7 +1295,8 @@ impl str { /// /// # Examples /// - /// This example manually iterates through the characters of a string; this should normally be + /// This example manually iterates through the characters of a string; + /// this should normally be /// done by `.chars()` or `.char_indices()`. /// /// ``` @@ -1072,7 +1347,8 @@ impl str { /// /// # Examples /// - /// This example manually iterates through the characters of a string; this should normally be + /// This example manually iterates through the characters of a string; + /// this should normally be /// done by `.chars().rev()` or `.char_indices()`. /// /// ``` @@ -1135,7 +1411,8 @@ impl str { core_str::StrExt::char_at(&self[..], i) } - /// Given a byte position, return the `char` at that position, counting from the end. + /// Given a byte position, return the `char` at that position, counting + /// from the end. /// /// # Panics /// @@ -1158,7 +1435,7 @@ impl str { core_str::StrExt::char_at_reverse(&self[..], i) } - /// Convert `self` to a byte slice. + /// Converts `self` to a byte slice. /// /// # Examples /// @@ -1170,31 +1447,36 @@ impl str { core_str::StrExt::as_bytes(&self[..]) } - /// Returns the byte index of the first character of `self` that matches the pattern, if it + /// Returns the byte index of the first character of `self` that matches + /// the pattern, if it /// exists. /// /// Returns `None` if it doesn't exist. /// - /// The pattern can be a simple `&str`, or a closure that determines the split. + /// The pattern can be a simple `&str`, `char`, or a closure that + /// determines the + /// split. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.find('L'), Some(0)); /// assert_eq!(s.find('é'), Some(14)); + /// assert_eq!(s.find("Léopard"), Some(13)); /// /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5)); + /// assert_eq!(s.find(char::is_lowercase), Some(1)); /// ``` /// /// Not finding the pattern: @@ -1210,16 +1492,18 @@ impl str { core_str::StrExt::find(&self[..], pat) } - /// Returns the byte index of the last character of `self` that matches the pattern, if it + /// Returns the byte index of the last character of `self` that + /// matches the pattern, if it /// exists. /// /// Returns `None` if it doesn't exist. /// - /// The pattern can be a simple `&str`, or a closure that determines the split. + /// The pattern can be a simple `&str`, `char`, + /// or a closure that determines the split. /// /// # Examples /// - /// Simple `&str` patterns: + /// Simple patterns: /// /// ``` /// let s = "Löwe 老虎 Léopard"; @@ -1228,12 +1512,13 @@ impl str { /// assert_eq!(s.rfind('é'), Some(14)); /// ``` /// - /// More complex patterns with a lambda: + /// More complex patterns with closures: /// /// ``` /// let s = "Löwe 老虎 Léopard"; /// /// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12)); + /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); /// ``` /// /// Not finding the pattern: @@ -1253,7 +1538,8 @@ impl str { /// Retrieves the first character from a `&str` and returns it. /// - /// This does not allocate a new string; instead, it returns a slice that points one character + /// This does not allocate a new string; instead, it returns a slice that + /// points one character /// beyond the character that was shifted. /// /// If the slice does not contain any characters, None is returned instead. @@ -1281,7 +1567,8 @@ impl str { core_str::StrExt::slice_shift_char(&self[..]) } - /// Returns the byte offset of an inner slice relative to an enclosing outer slice. + /// Returns the byte offset of an inner slice relative to an enclosing + /// outer slice. /// /// # Panics /// @@ -1304,9 +1591,10 @@ impl str { core_str::StrExt::subslice_offset(&self[..], inner) } - /// Return an unsafe pointer to the `&str`'s buffer. + /// Returns an unsafe pointer to the `&str`'s buffer. /// - /// The caller must ensure that the string outlives this pointer, and that it is not + /// The caller must ensure that the string outlives this pointer, and + /// that it is not /// reallocated (e.g. by pushing to the string). /// /// # Examples @@ -1321,7 +1609,7 @@ impl str { core_str::StrExt::as_ptr(&self[..]) } - /// Return an iterator of `u16` over the string encoded as UTF-16. + /// Returns an iterator of `u16` over the string encoded as UTF-16. #[unstable(feature = "collections", reason = "this functionality may only be provided by libunicode")] pub fn utf16_units(&self) -> Utf16Units { @@ -1382,7 +1670,8 @@ impl str { /// /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries /// - /// If `is_extended` is true, the iterator is over the *extended grapheme clusters*; + /// If `is_extended` is true, the iterator is over the + /// *extended grapheme clusters*; /// otherwise, the iterator is over the *legacy grapheme clusters*. /// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) /// recommends extended grapheme cluster boundaries for general processing. @@ -1407,7 +1696,8 @@ impl str { UnicodeStr::graphemes(&self[..], is_extended) } - /// Returns an iterator over the grapheme clusters of `self` and their byte offsets. See + /// Returns an iterator over the grapheme clusters of `self` and their + /// byte offsets. See /// `graphemes()` for more information. /// /// # Examples @@ -1427,7 +1717,8 @@ impl str { /// An iterator over the non-empty words of `self`. /// - /// A 'word' is a subsequence separated by any sequence of whitespace. Sequences of whitespace + /// A 'word' is a subsequence separated by any sequence of whitespace. + /// Sequences of whitespace /// are collapsed, so empty "words" are not included. /// /// # Examples @@ -1449,11 +1740,15 @@ impl str { /// /// Control characters have zero width. /// - /// `is_cjk` determines behavior for characters in the Ambiguous category: if `is_cjk` is - /// `true`, these are 2 columns wide; otherwise, they are 1. In CJK locales, `is_cjk` should be + /// `is_cjk` determines behavior for characters in the Ambiguous category: + /// if `is_cjk` is + /// `true`, these are 2 columns wide; otherwise, they are 1. + /// In CJK locales, `is_cjk` should be /// `true`, else it should be `false`. - /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) recommends that these - /// characters be treated as 1 column (i.e., `is_cjk = false`) if the locale is unknown. + /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/) + /// recommends that these + /// characters be treated as 1 column (i.e., `is_cjk = false`) if the + /// locale is unknown. #[unstable(feature = "unicode", reason = "this functionality may only be provided by libunicode")] pub fn width(&self, is_cjk: bool) -> usize { diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 7a77253209..0f0254a32b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -16,15 +16,14 @@ use core::prelude::*; -use core::default::Default; use core::fmt; use core::hash; -use core::iter::{IntoIterator, FromIterator}; +use core::iter::FromIterator; use core::mem; use core::ops::{self, Deref, Add, Index}; use core::ptr; use core::slice; -use core::str::Pattern; +use core::str::pattern::Pattern; use unicode::str as unicode_str; use unicode::str::Utf16Item; @@ -132,7 +131,7 @@ impl String { /// /// let invalid_vec = vec![240, 144, 128]; /// let s = String::from_utf8(invalid_vec).err().unwrap(); - /// assert_eq!(s.utf8_error(), Utf8Error::TooShort); + /// let err = s.utf8_error(); /// assert_eq!(s.into_bytes(), [240, 144, 128]); /// ``` #[inline] @@ -156,14 +155,10 @@ impl String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { - let mut i = 0; + let mut i; match str::from_utf8(v) { Ok(s) => return Cow::Borrowed(s), - Err(e) => { - if let Utf8Error::InvalidByte(firstbad) = e { - i = firstbad; - } - } + Err(e) => i = e.valid_up_to(), } const TAG_CONT_U8: u8 = 128; @@ -188,9 +183,9 @@ impl String { }; } - // subseqidx is the index of the first byte of the subsequence we're looking at. - // It's used to copy a bunch of contiguous good codepoints at once instead of copying - // them one by one. + // subseqidx is the index of the first byte of the subsequence we're + // looking at. It's used to copy a bunch of contiguous good codepoints + // at once instead of copying them one by one. let mut subseqidx = i; while i < total { @@ -347,7 +342,7 @@ impl String { String { vec: bytes } } - /// Return the underlying byte buffer, encoded as UTF-8. + /// Returns the underlying byte buffer, encoded as UTF-8. /// /// # Examples /// @@ -363,7 +358,7 @@ impl String { self.vec } - /// Extract a string slice containing the entire string. + /// Extracts a string slice containing the entire string. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -607,7 +602,7 @@ impl String { ch } - /// Insert a character into the string buffer at byte position `idx`. + /// Inserts a character into the string buffer at byte position `idx`. /// /// # Warning /// @@ -662,7 +657,7 @@ impl String { &mut self.vec } - /// Return the number of bytes in this string. + /// Returns the number of bytes in this string. /// /// # Examples /// @@ -705,12 +700,12 @@ impl String { } impl FromUtf8Error { - /// Consume this error, returning the bytes that were attempted to make a + /// Consumes this error, returning the bytes that were attempted to make a /// `String` with. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_bytes(self) -> Vec { self.bytes } - /// Access the underlying UTF8-error that was the cause of this error. + /// Accesss the underlying UTF8-error that was the cause of this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn utf8_error(&self) -> Utf8Error { self.error } } @@ -796,9 +791,9 @@ impl<'a, 'b> Pattern<'a> for &'b String { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for String { #[inline] - fn eq(&self, other: &String) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &String) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &String) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &String) -> bool { PartialEq::ne(&self[..], &other[..]) } } macro_rules! impl_eq { @@ -806,48 +801,41 @@ macro_rules! impl_eq { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> PartialEq<$rhs> for $lhs { #[inline] - fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &$rhs) -> bool { PartialEq::ne(&self[..], &other[..]) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> PartialEq<$lhs> for $rhs { #[inline] - fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &$lhs) -> bool { PartialEq::ne(&self[..], &other[..]) } } } } +impl_eq! { String, str } impl_eq! { String, &'a str } +impl_eq! { Cow<'a, str>, str } impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b> PartialEq<&'b str> for Cow<'a, str> { #[inline] - fn eq(&self, other: &&'b str) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &&'b str) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &&'b str) -> bool { PartialEq::ne(&**self, &**other) } + fn ne(&self, other: &&'b str) -> bool { PartialEq::ne(&self[..], &other[..]) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b> PartialEq> for &'b str { #[inline] - fn eq(&self, other: &Cow<'a, str>) -> bool { PartialEq::eq(&**self, &**other) } + fn eq(&self, other: &Cow<'a, str>) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] - fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&**self, &**other) } -} - -#[unstable(feature = "collections", reason = "waiting on Str stabilization")] -#[allow(deprecated)] -impl Str for String { - #[inline] - fn as_slice(&self) -> &str { - unsafe { mem::transmute(&*self.vec) } - } + fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&self[..], &other[..]) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -957,7 +945,7 @@ impl<'a> Deref for DerefString<'a> { } } -/// Convert a string slice to a wrapper type providing a `&String` reference. +/// Converts a string slice to a wrapper type providing a `&String` reference. /// /// # Examples /// @@ -1060,14 +1048,6 @@ impl<'a> IntoCow<'a, str> for &'a str { } } -#[allow(deprecated)] -impl<'a> Str for Cow<'a, str> { - #[inline] - fn as_slice<'b>(&'b self) -> &'b str { - &**self - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Write for String { #[inline] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 087b065031..526150915a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -53,11 +53,10 @@ use alloc::boxed::Box; use alloc::heap::{EMPTY, allocate, reallocate, deallocate}; use core::cmp::max; use core::cmp::Ordering; -use core::default::Default; use core::fmt; use core::hash::{self, Hash}; use core::intrinsics::assume; -use core::iter::{repeat, FromIterator, IntoIterator}; +use core::iter::{repeat, FromIterator}; use core::marker::PhantomData; use core::mem; use core::ops::{Index, IndexMut, Deref, Add}; @@ -65,10 +64,14 @@ use core::ops; use core::ptr; use core::ptr::Unique; use core::slice; +use core::isize; use core::usize; use borrow::{Cow, IntoCow}; +// FIXME- fix places which assume the max vector allowed has memory usize::MAX. +static MAX_MEMORY_SIZE: usize = isize::MAX as usize; + /// A growable list type, written `Vec` but pronounced 'vector.' /// /// # Examples @@ -185,7 +188,7 @@ impl Vec { /// # Examples /// /// ``` - /// let mut vec: Vec<_> = Vec::with_capacity(10); + /// let mut vec = Vec::with_capacity(10); /// /// // The vector contains no items, even though it has capacity for more /// assert_eq!(vec.len(), 0); @@ -307,10 +310,15 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { if self.cap - self.len < additional { - let err_msg = "Vec::reserve: `usize` overflow"; - let new_cap = self.len.checked_add(additional).expect(err_msg) - .checked_next_power_of_two().expect(err_msg); - self.grow_capacity(new_cap); + 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, + }); } } @@ -384,7 +392,7 @@ impl Vec { } } - /// Convert the vector into Box<[T]>. + /// Converts the vector into Box<[T]>. /// /// Note that this will drop any excess capacity. Calling this and /// converting back to a vector with `into_vec()` is equivalent to calling @@ -425,7 +433,7 @@ impl Vec { } } - /// Extract a slice containing the entire vector. + /// Extracts a slice containing the entire vector. #[inline] #[unstable(feature = "convert", reason = "waiting on RFC revision")] @@ -441,37 +449,6 @@ impl Vec { &mut self[..] } - /// Creates a consuming iterator, that is, one that moves each value out of - /// the vector (from start to end). The vector cannot be used after calling - /// this. - /// - /// # Examples - /// - /// ``` - /// let v = vec!["a".to_string(), "b".to_string()]; - /// for s in v.into_iter() { - /// // s has type String, not &String - /// println!("{}", s); - /// } - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - unsafe { - let ptr = *self.ptr; - assume(!ptr.is_null()); - let cap = self.cap; - let begin = ptr as *const T; - let end = if mem::size_of::() == 0 { - (ptr as usize + self.len()) as *const T - } else { - ptr.offset(self.len() as isize) as *const T - }; - mem::forget(self); - IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end } - } - } - /// Sets the length of a vector. /// /// This will explicitly set the size of the vector, without actually @@ -525,8 +502,7 @@ impl Vec { /// /// # Panics /// - /// Panics if `index` is not between `0` and the vector's length (both - /// bounds inclusive). + /// Panics if `index` is greater than the vector's length. /// /// # Examples /// @@ -648,8 +624,11 @@ impl Vec { #[inline(never)] fn resize(vec: &mut Vec) { let old_size = vec.cap * mem::size_of::(); - let size = max(old_size, 2 * mem::size_of::()) * 2; - if old_size > size { panic!("capacity overflow") } + 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() } @@ -1501,8 +1480,34 @@ impl IntoIterator for Vec { type Item = T; type IntoIter = IntoIter; + /// Creates a consuming iterator, that is, one that moves each value out of + /// the vector (from start to end). The vector cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// let v = vec!["a".to_string(), "b".to_string()]; + /// for s in v.into_iter() { + /// // s has type String, not &String + /// println!("{}", s); + /// } + /// ``` + #[inline] fn into_iter(self) -> IntoIter { - self.into_iter() + unsafe { + let ptr = *self.ptr; + assume(!ptr.is_null()); + let cap = self.cap; + let begin = ptr as *const T; + let end = if mem::size_of::() == 0 { + (ptr as usize + self.len()) as *const T + } else { + ptr.offset(self.len() as isize) as *const T + }; + mem::forget(self); + IntoIter { allocation: ptr, cap: cap, ptr: begin, end: end } + } } } @@ -1586,18 +1591,6 @@ impl Ord for Vec { } } -#[unstable(feature = "collections", - reason = "will be replaced by slice syntax")] -#[deprecated(since = "1.0.0", reason = "use &mut s[..] instead")] -#[allow(deprecated)] -impl AsSlice for Vec { - /// Deprecated: use `&mut s[..]` instead. - #[inline] - fn as_slice(&self) -> &[T] { - self - } -} - #[unstable(feature = "collections", reason = "recent addition, needs more experience")] impl<'a, T: Clone> Add<&'a [T]> for Vec { @@ -1925,7 +1918,7 @@ impl<'a, T> Drop for DerefVec<'a, T> { } } -/// Convert a slice to a wrapper type providing a `&Vec` reference. +/// Converts a slice to a wrapper type providing a `&Vec` reference. #[unstable(feature = "collections")] pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> { unsafe { diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 49b0c22921..bbe7830b42 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -21,9 +21,8 @@ use core::prelude::*; use core::cmp::Ordering; -use core::default::Default; use core::fmt; -use core::iter::{self, repeat, FromIterator, IntoIterator, RandomAccessIterator}; +use core::iter::{self, repeat, FromIterator, RandomAccessIterator}; use core::mem; use core::ops::{Index, IndexMut}; use core::ptr::{self, Unique}; @@ -224,11 +223,8 @@ impl VecDeque { /// buf.push_back(3); /// buf.push_back(4); /// buf.push_back(5); - /// match buf.get_mut(1) { - /// None => {} - /// Some(elem) => { - /// *elem = 7; - /// } + /// if let Some(elem) = buf.get_mut(1) { + /// *elem = 7; /// } /// /// assert_eq!(buf[1], 7); @@ -481,7 +477,7 @@ impl VecDeque { } } - /// Shorten a ringbuf, dropping excess elements from the back. + /// Shortens a ringbuf, dropping excess elements from the back. /// /// If `len` is greater than the ringbuf's current length, this has no /// effect. @@ -560,14 +556,6 @@ impl VecDeque { } } - /// Consumes the list into a front-to-back iterator yielding elements by value. - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - IntoIter { - inner: self, - } - } - /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. #[inline] @@ -1731,8 +1719,12 @@ impl IntoIterator for VecDeque { type Item = T; type IntoIter = IntoIter; + /// Consumes the list into a front-to-back iterator yielding elements by + /// value. fn into_iter(self) -> IntoIter { - self.into_iter() + IntoIter { + inner: self, + } } } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 8900c79504..d473504d54 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -18,10 +18,9 @@ use self::Entry::*; use core::prelude::*; use core::cmp::{max, Ordering}; -use core::default::Default; use core::fmt; use core::hash::{Hash, Hasher}; -use core::iter::{Enumerate, FilterMap, Map, FromIterator, IntoIterator}; +use core::iter::{Enumerate, FilterMap, Map, FromIterator}; use core::iter; use core::mem::{replace, swap}; use core::ops::{Index, IndexMut}; @@ -48,9 +47,8 @@ use vec::Vec; /// /// assert_eq!(months.get(&1), Some(&"Jan")); /// -/// match months.get_mut(&3) { -/// Some(value) => *value = "Venus", -/// None => (), +/// if let Some(value) = months.get_mut(&3) { +/// *value = "Venus"; /// } /// /// assert_eq!(months.get(&3), Some(&"Venus")); @@ -302,35 +300,6 @@ impl VecMap { } } - /// Returns an iterator visiting all key-value pairs in ascending order of - /// the keys, consuming the original `VecMap`. - /// The iterator's element type is `(usize, &'r V)`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(collections)] - /// use std::collections::VecMap; - /// - /// let mut map = VecMap::new(); - /// map.insert(1, "a"); - /// map.insert(3, "c"); - /// map.insert(2, "b"); - /// - /// let vec: Vec<(usize, &str)> = map.into_iter().collect(); - /// - /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - fn filter((i, v): (usize, Option)) -> Option<(usize, A)> { - v.map(|v| (i, v)) - } - let filter: fn((usize, Option)) -> Option<(usize, V)> = filter; // coerce to fn ptr - - IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) } - } - /// Moves all elements from `other` into the map while overwriting existing keys. /// /// # Examples @@ -452,7 +421,7 @@ impl VecMap { Drain { iter: self.v.drain().enumerate().filter_map(filter) } } - /// Return the number of elements in the map. + /// Returns the number of elements in the map. /// /// # Examples /// @@ -470,7 +439,7 @@ impl VecMap { self.v.iter().filter(|elt| elt.is_some()).count() } - /// Return true if the map contains no elements. + /// Returns true if the map contains no elements. /// /// # Examples /// @@ -558,9 +527,8 @@ impl VecMap { /// /// let mut map = VecMap::new(); /// map.insert(1, "a"); - /// match map.get_mut(&1) { - /// Some(x) => *x = "b", - /// None => (), + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; /// } /// assert_eq!(map[1], "b"); /// ``` @@ -576,7 +544,7 @@ impl VecMap { } } - /// Inserts a key-value pair from the map. If the key already had a value + /// Inserts a key-value pair into the map. If the key already had a value /// present in the map, that value is returned. Otherwise, `None` is returned. /// /// # Examples @@ -802,8 +770,32 @@ impl IntoIterator for VecMap { type Item = (usize, T); type IntoIter = IntoIter; + /// Returns an iterator visiting all key-value pairs in ascending order of + /// the keys, consuming the original `VecMap`. + /// The iterator's element type is `(usize, &'r V)`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections)] + /// use std::collections::VecMap; + /// + /// let mut map = VecMap::new(); + /// map.insert(1, "a"); + /// map.insert(3, "c"); + /// map.insert(2, "b"); + /// + /// let vec: Vec<(usize, &str)> = map.into_iter().collect(); + /// + /// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]); + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + fn filter((i, v): (usize, Option)) -> Option<(usize, A)> { + v.map(|v| (i, v)) + } + let filter: fn((usize, Option)) -> Option<(usize, T)> = filter; // coerce to fn ptr + + IntoIter { iter: self.v.into_iter().enumerate().filter_map(filter) } } } diff --git a/src/libcollectionstest/bench.rs b/src/libcollectionstest/bench.rs index 8f2e71b666..4e150d4a22 100644 --- a/src/libcollectionstest/bench.rs +++ b/src/libcollectionstest/bench.rs @@ -12,14 +12,13 @@ macro_rules! map_insert_rand_bench { ($name: ident, $n: expr, $map: ident) => ( #[bench] pub fn $name(b: &mut ::test::Bencher) { - use std::rand; - use std::rand::Rng; + use std::__rand::{thread_rng, Rng}; use test::black_box; let n: usize = $n; let mut map = $map::new(); // setup - let mut rng = rand::weak_rng(); + let mut rng = thread_rng(); for _ in 0..n { let i = rng.gen::() % n; @@ -67,8 +66,7 @@ macro_rules! map_find_rand_bench { #[bench] pub fn $name(b: &mut ::test::Bencher) { use std::iter::Iterator; - use std::rand::Rng; - use std::rand; + use std::__rand::{thread_rng, Rng}; use std::vec::Vec; use test::black_box; @@ -76,7 +74,7 @@ macro_rules! map_find_rand_bench { let n: usize = $n; // setup - let mut rng = rand::weak_rng(); + let mut rng = thread_rng(); let mut keys: Vec<_> = (0..n).map(|_| rng.gen::() % n).collect(); for &k in &keys { diff --git a/src/libcollectionstest/bit/set.rs b/src/libcollectionstest/bit/set.rs index 19ea25ee34..d020f551dd 100644 --- a/src/libcollectionstest/bit/set.rs +++ b/src/libcollectionstest/bit/set.rs @@ -389,16 +389,15 @@ fn test_bit_vec_clone() { mod bench { use std::collections::{BitSet, BitVec}; - use std::rand::{Rng, self}; + use std::__rand::{Rng, thread_rng, ThreadRng}; use std::u32; use test::{Bencher, black_box}; const BENCH_BITS : usize = 1 << 14; - fn rng() -> rand::IsaacRng { - let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::SeedableRng::from_seed(seed) + fn rng() -> ThreadRng { + thread_rng() } #[bench] @@ -407,7 +406,7 @@ mod bench { let mut bit_vec = BitSet::new(); b.iter(|| { for _ in 0..100 { - bit_vec.insert((r.next_u32() as usize) % u32::BITS as usize); + bit_vec.insert((r.next_u32() as usize) % u32::BITS); } black_box(&bit_vec); }); diff --git a/src/libcollectionstest/bit/vec.rs b/src/libcollectionstest/bit/vec.rs index 3826974d1a..3cddaef079 100644 --- a/src/libcollectionstest/bit/vec.rs +++ b/src/libcollectionstest/bit/vec.rs @@ -541,43 +541,43 @@ fn test_big_bit_vec_tests() { #[test] fn test_bit_vec_push_pop() { - let mut s = BitVec::from_elem(5 * u32::BITS as usize - 2, false); - assert_eq!(s.len(), 5 * u32::BITS as usize - 2); - assert_eq!(s[5 * u32::BITS as usize - 3], false); + let mut s = BitVec::from_elem(5 * u32::BITS - 2, false); + assert_eq!(s.len(), 5 * u32::BITS - 2); + assert_eq!(s[5 * u32::BITS - 3], false); s.push(true); s.push(true); - assert_eq!(s[5 * u32::BITS as usize - 2], true); - assert_eq!(s[5 * u32::BITS as usize - 1], true); + assert_eq!(s[5 * u32::BITS - 2], true); + assert_eq!(s[5 * u32::BITS - 1], true); // Here the internal vector will need to be extended s.push(false); - assert_eq!(s[5 * u32::BITS as usize], false); + assert_eq!(s[5 * u32::BITS], false); s.push(false); - assert_eq!(s[5 * u32::BITS as usize + 1], false); - assert_eq!(s.len(), 5 * u32::BITS as usize + 2); + assert_eq!(s[5 * u32::BITS + 1], false); + assert_eq!(s.len(), 5 * u32::BITS + 2); // Pop it all off assert_eq!(s.pop(), Some(false)); assert_eq!(s.pop(), Some(false)); assert_eq!(s.pop(), Some(true)); assert_eq!(s.pop(), Some(true)); - assert_eq!(s.len(), 5 * u32::BITS as usize - 2); + assert_eq!(s.len(), 5 * u32::BITS - 2); } #[test] fn test_bit_vec_truncate() { - let mut s = BitVec::from_elem(5 * u32::BITS as usize, true); + let mut s = BitVec::from_elem(5 * u32::BITS, true); - assert_eq!(s, BitVec::from_elem(5 * u32::BITS as usize, true)); - assert_eq!(s.len(), 5 * u32::BITS as usize); - s.truncate(4 * u32::BITS as usize); - assert_eq!(s, BitVec::from_elem(4 * u32::BITS as usize, true)); - assert_eq!(s.len(), 4 * u32::BITS as usize); + assert_eq!(s, BitVec::from_elem(5 * u32::BITS, true)); + assert_eq!(s.len(), 5 * u32::BITS); + s.truncate(4 * u32::BITS); + assert_eq!(s, BitVec::from_elem(4 * u32::BITS, true)); + assert_eq!(s.len(), 4 * u32::BITS); // Truncating to a size > s.len() should be a noop - s.truncate(5 * u32::BITS as usize); - assert_eq!(s, BitVec::from_elem(4 * u32::BITS as usize, true)); - assert_eq!(s.len(), 4 * u32::BITS as usize); - s.truncate(3 * u32::BITS as usize - 10); - assert_eq!(s, BitVec::from_elem(3 * u32::BITS as usize - 10, true)); - assert_eq!(s.len(), 3 * u32::BITS as usize - 10); + s.truncate(5 * u32::BITS); + assert_eq!(s, BitVec::from_elem(4 * u32::BITS, true)); + assert_eq!(s.len(), 4 * u32::BITS); + s.truncate(3 * u32::BITS - 10); + assert_eq!(s, BitVec::from_elem(3 * u32::BITS - 10, true)); + assert_eq!(s.len(), 3 * u32::BITS - 10); s.truncate(0); assert_eq!(s, BitVec::from_elem(0, true)); assert_eq!(s.len(), 0); @@ -585,26 +585,26 @@ fn test_bit_vec_truncate() { #[test] fn test_bit_vec_reserve() { - let mut s = BitVec::from_elem(5 * u32::BITS as usize, true); + let mut s = BitVec::from_elem(5 * u32::BITS, true); // Check capacity - assert!(s.capacity() >= 5 * u32::BITS as usize); - s.reserve(2 * u32::BITS as usize); - assert!(s.capacity() >= 7 * u32::BITS as usize); - s.reserve(7 * u32::BITS as usize); - assert!(s.capacity() >= 12 * u32::BITS as usize); - s.reserve_exact(7 * u32::BITS as usize); - assert!(s.capacity() >= 12 * u32::BITS as usize); - s.reserve(7 * u32::BITS as usize + 1); - assert!(s.capacity() >= 12 * u32::BITS as usize + 1); + assert!(s.capacity() >= 5 * u32::BITS); + s.reserve(2 * u32::BITS); + assert!(s.capacity() >= 7 * u32::BITS); + s.reserve(7 * u32::BITS); + assert!(s.capacity() >= 12 * u32::BITS); + s.reserve_exact(7 * u32::BITS); + assert!(s.capacity() >= 12 * u32::BITS); + s.reserve(7 * u32::BITS + 1); + assert!(s.capacity() >= 12 * u32::BITS + 1); // Check that length hasn't changed - assert_eq!(s.len(), 5 * u32::BITS as usize); + assert_eq!(s.len(), 5 * u32::BITS); s.push(true); s.push(false); s.push(true); - assert_eq!(s[5 * u32::BITS as usize - 1], true); - assert_eq!(s[5 * u32::BITS as usize - 0], true); - assert_eq!(s[5 * u32::BITS as usize + 1], false); - assert_eq!(s[5 * u32::BITS as usize + 2], true); + assert_eq!(s[5 * u32::BITS - 1], true); + assert_eq!(s[5 * u32::BITS - 0], true); + assert_eq!(s[5 * u32::BITS + 1], false); + assert_eq!(s[5 * u32::BITS + 2], true); } #[test] @@ -633,15 +633,14 @@ fn test_bit_vec_extend() { mod bench { use std::collections::BitVec; use std::u32; - use std::rand::{Rng, self}; + use std::__rand::{Rng, thread_rng, ThreadRng}; use test::{Bencher, black_box}; const BENCH_BITS : usize = 1 << 14; - fn rng() -> rand::IsaacRng { - let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::SeedableRng::from_seed(seed) + fn rng() -> ThreadRng { + thread_rng() } #[bench] @@ -650,7 +649,7 @@ mod bench { let mut bit_vec = 0 as usize; b.iter(|| { for _ in 0..100 { - bit_vec |= 1 << ((r.next_u32() as usize) % u32::BITS as usize); + bit_vec |= 1 << ((r.next_u32() as usize) % u32::BITS); } black_box(&bit_vec); }); @@ -683,10 +682,10 @@ mod bench { #[bench] fn bench_bit_set_small(b: &mut Bencher) { let mut r = rng(); - let mut bit_vec = BitVec::from_elem(u32::BITS as usize, false); + let mut bit_vec = BitVec::from_elem(u32::BITS, false); b.iter(|| { for _ in 0..100 { - bit_vec.set((r.next_u32() as usize) % u32::BITS as usize, true); + bit_vec.set((r.next_u32() as usize) % u32::BITS, true); } black_box(&bit_vec); }); @@ -703,7 +702,7 @@ mod bench { #[bench] fn bench_bit_vec_small_iter(b: &mut Bencher) { - let bit_vec = BitVec::from_elem(u32::BITS as usize, false); + let bit_vec = BitVec::from_elem(u32::BITS, false); b.iter(|| { let mut sum = 0; for _ in 0..10 { diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollectionstest/btree/map.rs index 10d69c9f5e..a29968ae8a 100644 --- a/src/libcollectionstest/btree/map.rs +++ b/src/libcollectionstest/btree/map.rs @@ -251,7 +251,7 @@ fn test_entry(){ mod bench { use std::collections::BTreeMap; - use std::rand::{Rng, weak_rng}; + use std::__rand::{Rng, thread_rng}; use test::{Bencher, black_box}; @@ -269,7 +269,7 @@ mod bench { fn bench_iter(b: &mut Bencher, size: i32) { let mut map = BTreeMap::::new(); - let mut rng = weak_rng(); + let mut rng = thread_rng(); for _ in 0..size { map.insert(rng.gen(), rng.gen()); diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index 5b0aceb76d..e1c4e05e19 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering::{Equal, Greater, Less}; use std::default::Default; use std::iter::RandomAccessIterator; use std::mem; -use std::rand::{Rng, thread_rng}; +use std::__rand::{Rng, thread_rng}; use std::rc::Rc; use std::slice::ElementSwaps; @@ -1296,7 +1296,7 @@ fn test_to_vec() { mod bench { use std::iter::repeat; use std::{mem, ptr}; - use std::rand::{Rng, weak_rng}; + use std::__rand::{Rng, thread_rng}; use test::{Bencher, black_box}; @@ -1465,7 +1465,7 @@ mod bench { #[bench] fn random_inserts(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = repeat((0, 0)).take(30).collect(); for _ in 0..100 { @@ -1477,7 +1477,7 @@ mod bench { } #[bench] fn random_removes(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = repeat((0, 0)).take(130).collect(); for _ in 0..100 { @@ -1489,7 +1489,7 @@ mod bench { #[bench] fn sort_random_small(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(5).collect(); v.sort(); @@ -1499,7 +1499,7 @@ mod bench { #[bench] fn sort_random_medium(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(100).collect(); v.sort(); @@ -1509,7 +1509,7 @@ mod bench { #[bench] fn sort_random_large(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v: Vec<_> = rng.gen_iter::().take(10000).collect(); v.sort(); @@ -1530,7 +1530,7 @@ mod bench { #[bench] fn sort_big_random_small(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(5) .collect::>(); @@ -1541,7 +1541,7 @@ mod bench { #[bench] fn sort_big_random_medium(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(100) .collect::>(); @@ -1552,7 +1552,7 @@ mod bench { #[bench] fn sort_big_random_large(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { let mut v = rng.gen_iter::().take(10000) .collect::>(); diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index 495a961fa3..cacafab4e3 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,7 +9,6 @@ // except according to those terms. use std::cmp::Ordering::{Equal, Greater, Less}; -use std::iter::AdditiveIterator; use std::str::{Utf8Error, from_utf8}; #[test] @@ -1503,7 +1502,404 @@ fn test_str_from_utf8() { assert_eq!(from_utf8(xs), Ok("ศไทย中华Việt Nam")); let xs = b"hello\xFF"; - assert_eq!(from_utf8(xs), Err(Utf8Error::TooShort)); + assert!(from_utf8(xs).is_err()); +} + +#[test] +fn test_pattern_deref_forward() { + let data = "aabcdaa"; + assert!(data.contains("bcd")); + assert!(data.contains(&"bcd")); + assert!(data.contains(&"bcd".to_string())); +} + +#[test] +fn test_empty_match_indices() { + let data = "aä中!"; + let vec: Vec<_> = data.match_indices("").collect(); + assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]); +} + +#[test] +fn test_bool_from_str() { + assert_eq!("true".parse().ok(), Some(true)); + assert_eq!("false".parse().ok(), Some(false)); + assert_eq!("not even a boolean".parse::().ok(), None); +} + +fn check_contains_all_substrings(s: &str) { + assert!(s.contains("")); + for i in 0..s.len() { + for j in i+1..s.len() + 1 { + assert!(s.contains(&s[i..j])); + } + } +} + +#[test] +fn strslice_issue_16589() { + assert!("bananas".contains("nana")); + + // prior to the fix for #16589, x.contains("abcdabcd") returned false + // test all substrings for good measure + check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd"); +} + +#[test] +fn strslice_issue_16878() { + assert!(!"1234567ah012345678901ah".contains("hah")); + assert!(!"00abc01234567890123456789abc".contains("bcabc")); +} + + +#[test] +fn test_strslice_contains() { + let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; + check_contains_all_substrings(x); +} + +#[test] +fn test_rsplitn_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); + + // Unicode + let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); + + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); + split.reverse(); + assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); +} + +#[test] +fn test_split_char_iterator() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split(' ').collect(); + assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut rsplit: Vec<&str> = data.split(' ').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let split: Vec<&str> = data.split(|c: char| c == ' ').collect(); + assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); + + // Unicode + let split: Vec<&str> = data.split('ä').collect(); + assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let mut rsplit: Vec<&str> = data.split('ä').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let split: Vec<&str> = data.split(|c: char| c == 'ä').collect(); + assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); + + let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect(); + rsplit.reverse(); + assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); +} + +#[test] +fn test_rev_split_char_iterator_no_trailing() { + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let mut split: Vec<&str> = data.split('\n').rev().collect(); + split.reverse(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); + + let mut split: Vec<&str> = data.split_terminator('\n').rev().collect(); + split.reverse(); + assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); +} + +#[test] +fn test_utf16_code_units() { + use unicode::str::Utf16Encoder; + assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), + [0xE9, 0xD83D, 0xDCA9]) +} + +#[test] +fn starts_with_in_unicode() { + assert!(!"├── Cargo.toml".starts_with("# ")); +} + +#[test] +fn starts_short_long() { + assert!(!"".starts_with("##")); + assert!(!"##".starts_with("####")); + assert!("####".starts_with("##")); + assert!(!"##ä".starts_with("####")); + assert!("####ä".starts_with("##")); + assert!(!"##".starts_with("####ä")); + assert!("##ä##".starts_with("##ä")); + + assert!("".starts_with("")); + assert!("ä".starts_with("")); + assert!("#ä".starts_with("")); + assert!("##ä".starts_with("")); + assert!("ä###".starts_with("")); + assert!("#ä##".starts_with("")); + assert!("##ä#".starts_with("")); +} + +#[test] +fn contains_weird_cases() { + assert!("* \t".contains(' ')); + assert!(!"* \t".contains('?')); + assert!(!"* \t".contains('\u{1F4A9}')); +} + +#[test] +fn trim_ws() { + assert_eq!(" \t a \t ".trim_left_matches(|c: char| c.is_whitespace()), + "a \t "); + assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()), + " \t a"); + assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), + "a"); + assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()), + ""); + assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()), + ""); + assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), + ""); +} + +mod pattern { + use std::str::pattern::Pattern; + use std::str::pattern::{Searcher, ReverseSearcher}; + use std::str::pattern::SearchStep::{self, Match, Reject, Done}; + + macro_rules! make_test { + ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => { + mod $name { + use std::str::pattern::SearchStep::{Match, Reject}; + use super::{cmp_search_to_vec}; + #[test] + fn fwd() { + cmp_search_to_vec(false, $p, $h, vec![$($e),*]); + } + #[test] + fn bwd() { + cmp_search_to_vec(true, $p, $h, vec![$($e),*]); + } + } + } + } + + fn cmp_search_to_vec<'a, P: Pattern<'a>>(rev: bool, pat: P, haystack: &'a str, + right: Vec) + where P::Searcher: ReverseSearcher<'a> + { + let mut searcher = pat.into_searcher(haystack); + let mut v = vec![]; + loop { + match if !rev {searcher.next()} else {searcher.next_back()} { + Match(a, b) => v.push(Match(a, b)), + Reject(a, b) => v.push(Reject(a, b)), + Done => break, + } + } + if rev { + v.reverse(); + } + + let mut first_index = 0; + let mut err = None; + + for (i, e) in right.iter().enumerate() { + match *e { + Match(a, b) | Reject(a, b) + if a <= b && a == first_index => { + first_index = b; + } + _ => { + err = Some(i); + break; + } + } + } + + if let Some(err) = err { + panic!("Input skipped range at {}", err); + } + + if first_index != haystack.len() { + panic!("Did not cover whole input"); + } + + assert_eq!(v, right); + } + + make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [ + Reject(0, 1), + Match (1, 3), + Reject(3, 4), + Match (4, 6), + Reject(6, 7), + ]); + make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ + Match (0, 0), + Reject(0, 1), + Match (1, 1), + Reject(1, 2), + Match (2, 2), + Reject(2, 3), + Match (3, 3), + Reject(3, 4), + Match (4, 4), + Reject(4, 5), + Match (5, 5), + Reject(5, 6), + Match (6, 6), + Reject(6, 7), + Match (7, 7), + ]); + make_test!(str_searcher_mulibyte_haystack, " ", "├──", [ + Reject(0, 3), + Reject(3, 6), + Reject(6, 9), + ]); + make_test!(str_searcher_empty_needle_mulibyte_haystack, "", "├──", [ + Match (0, 0), + Reject(0, 3), + Match (3, 3), + Reject(3, 6), + Match (6, 6), + Reject(6, 9), + Match (9, 9), + ]); + make_test!(str_searcher_empty_needle_empty_haystack, "", "", [ + Match(0, 0), + ]); + make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", [ + ]); + make_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", [ + Reject(0, 1), + Match (1, 2), + Match (2, 3), + Reject(3, 4), + Match (4, 5), + Match (5, 6), + Reject(6, 7), + ]); + make_test!(char_searcher_mulibyte_haystack, ' ', "├──", [ + Reject(0, 3), + Reject(3, 6), + Reject(6, 9), + ]); + make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [ + Reject(0, 1), + Reject(1, 2), + Reject(2, 3), + ]); + +} + +macro_rules! generate_iterator_test { + { + $name:ident { + $( + ($($arg:expr),*) -> [$($t:tt)*]; + )* + } + with $fwd:expr, $bwd:expr; + } => { + #[test] + fn $name() { + $( + { + let res = vec![$($t)*]; + + let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); + assert_eq!(fwd_vec, res); + + let mut bwd_vec: Vec<_> = ($bwd)($($arg),*).collect(); + bwd_vec.reverse(); + assert_eq!(bwd_vec, res); + } + )* + } + }; + { + $name:ident { + $( + ($($arg:expr),*) -> [$($t:tt)*]; + )* + } + with $fwd:expr; + } => { + #[test] + fn $name() { + $( + { + let res = vec![$($t)*]; + + let fwd_vec: Vec<_> = ($fwd)($($arg),*).collect(); + assert_eq!(fwd_vec, res); + } + )* + } + } +} + +generate_iterator_test! { + double_ended_split { + ("foo.bar.baz", '.') -> ["foo", "bar", "baz"]; + ("foo::bar::baz", "::") -> ["foo", "bar", "baz"]; + } + with str::split, str::rsplit; +} + +generate_iterator_test! { + double_ended_split_terminator { + ("foo;bar;baz;", ';') -> ["foo", "bar", "baz"]; + } + with str::split_terminator, str::rsplit_terminator; +} + +generate_iterator_test! { + double_ended_matches { + ("a1b2c3", char::is_numeric) -> ["1", "2", "3"]; + } + with str::matches, str::rmatches; +} + +generate_iterator_test! { + double_ended_match_indices { + ("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)]; + } + with str::match_indices, str::rmatch_indices; +} + +generate_iterator_test! { + not_double_ended_splitn { + ("foo::bar::baz", 2, "::") -> ["foo", "bar::baz"]; + } + with str::splitn; +} + +generate_iterator_test! { + not_double_ended_rsplitn { + ("foo::bar::baz", 2, "::") -> ["baz", "foo::bar"]; + } + with str::rsplitn; } mod bench { @@ -1693,4 +2089,106 @@ malesuada sollicitudin quam eu fermentum."; assert!(haystack.contains(needle)); }) } + + macro_rules! make_test_inner { + ($s:ident, $code:expr, $name:ident, $str:expr) => { + #[bench] + fn $name(bencher: &mut Bencher) { + let mut $s = $str; + black_box(&mut $s); + bencher.iter(|| $code); + } + } + } + + macro_rules! make_test { + ($name:ident, $s:ident, $code:expr) => { + mod $name { + use test::Bencher; + use test::black_box; + + // Short strings: 65 bytes each + make_test_inner!($s, $code, short_ascii, + "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!"); + make_test_inner!($s, $code, short_mixed, + "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!"); + make_test_inner!($s, $code, short_pile_of_poo, + "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!"); + make_test_inner!($s, $code, long_lorem_ipsum,"\ +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ +ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ +eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ +sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ +tempus vel, gravida nec quam. + +In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ +sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ +diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ +lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ +eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ +interdum. Curabitur ut nisi justo. + +Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ +mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ +lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ +est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ +felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ +ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ +feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ +Aliquam sit amet placerat lorem. + +Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ +mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ +Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ +lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ +suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ +cursus accumsan. + +Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ +feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ +vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ +leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ +malesuada sollicitudin quam eu fermentum!"); + } + } + } + + make_test!(chars_count, s, s.chars().count()); + + make_test!(contains_bang_str, s, s.contains("!")); + make_test!(contains_bang_char, s, s.contains('!')); + + make_test!(match_indices_a_str, s, s.match_indices("a").count()); + + make_test!(split_a_str, s, s.split("a").count()); + + make_test!(trim_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_matches(|c: char| c.is_ascii()) + }); + make_test!(trim_left_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_left_matches(|c: char| c.is_ascii()) + }); + make_test!(trim_right_ascii_char, s, { + use std::ascii::AsciiExt; + s.trim_right_matches(|c: char| c.is_ascii()) + }); + + make_test!(find_underscore_char, s, s.find('_')); + make_test!(rfind_underscore_char, s, s.rfind('_')); + make_test!(find_underscore_str, s, s.find("_")); + + make_test!(find_zzz_char, s, s.find('\u{1F4A4}')); + make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}')); + make_test!(find_zzz_str, s, s.find("\u{1F4A4}")); + + make_test!(split_space_char, s, s.split(' ').count()); + make_test!(split_terminator_space_char, s, s.split_terminator(' ').count()); + + make_test!(splitn_space_char, s, s.splitn(10, ' ').count()); + make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); + + make_test!(split_space_str, s, s.split(" ").count()); + make_test!(split_ad_str, s, s.split("ad").count()); } diff --git a/src/libcollectionstest/string.rs b/src/libcollectionstest/string.rs index 5d6aa8ac0d..3184f842e9 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollectionstest/string.rs @@ -45,7 +45,6 @@ fn test_from_utf8() { let xs = b"hello\xFF".to_vec(); let err = String::from_utf8(xs).err().unwrap(); - assert_eq!(err.utf8_error(), Utf8Error::TooShort); assert_eq!(err.into_bytes(), b"hello\xff".to_vec()); } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 320fdd50b3..85b8accadf 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -83,14 +83,15 @@ use marker::{Reflect, Sized}; // Any trait /////////////////////////////////////////////////////////////////////////////// -/// A type to emulate dynamic typing. See the [module-level documentation][mod] for more details. +/// A type to emulate dynamic typing. /// /// Every type with no non-`'static` references implements `Any`. +/// See the [module-level documentation][mod] for more details. /// -/// [mod]: ../index.html +/// [mod]: index.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Any: Reflect + 'static { - /// Get the `TypeId` of `self` + /// Gets the `TypeId` of `self`. #[unstable(feature = "core", reason = "this method will likely be replaced by an associated static")] fn get_type_id(&self) -> TypeId; @@ -113,6 +114,16 @@ impl fmt::Debug for Any { } } +// Ensure that the result of e.g. joining a thread can be printed and +// hence used with `unwrap`. May eventually no longer be needed if +// dispatch works with upcasting. +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Any + Send { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + impl Any { /// Returns true if the boxed type is the same as `T` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index ed35e09549..02f9ee506f 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -78,12 +78,20 @@ use intrinsics; use cell::UnsafeCell; use marker::PhantomData; +use default::Default; + /// A boolean type which can be safely shared between threads. #[stable(feature = "rust1", since = "1.0.0")] pub struct AtomicBool { v: UnsafeCell, } +impl Default for AtomicBool { + fn default() -> AtomicBool { + ATOMIC_BOOL_INIT + } +} + unsafe impl Sync for AtomicBool {} /// A signed integer type which can be safely shared between threads. @@ -92,6 +100,12 @@ pub struct AtomicIsize { v: UnsafeCell, } +impl Default for AtomicIsize { + fn default() -> AtomicIsize { + ATOMIC_ISIZE_INIT + } +} + unsafe impl Sync for AtomicIsize {} /// An unsigned integer type which can be safely shared between threads. @@ -100,6 +114,12 @@ pub struct AtomicUsize { v: UnsafeCell, } +impl Default for AtomicUsize { + fn default() -> AtomicUsize { + ATOMIC_USIZE_INIT + } +} + unsafe impl Sync for AtomicUsize {} /// A raw pointer type which can be safely shared between threads. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 76e09eedbd..df0de234b9 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -211,7 +211,7 @@ impl Cell { } } - /// Get a reference to the underlying `UnsafeCell`. + /// Gets a reference to the underlying `UnsafeCell`. /// /// # Unsafety /// @@ -436,7 +436,7 @@ impl RefCell { } } - /// Get a reference to the underlying `UnsafeCell`. + /// Gets a reference to the underlying `UnsafeCell`. /// /// This can be used to circumvent `RefCell`'s safety checks. /// @@ -537,7 +537,7 @@ impl<'b, T> Deref for Ref<'b, T> { } } -/// Copy a `Ref`. +/// Copies a `Ref`. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. /// @@ -647,7 +647,7 @@ pub struct UnsafeCell { impl !Sync for UnsafeCell {} impl UnsafeCell { - /// Construct a new instance of `UnsafeCell` which will wrap the specified + /// Constructs a new instance of `UnsafeCell` which will wrap the specified /// value. /// /// All access to the inner value through methods is `unsafe`, and it is highly discouraged to @@ -685,7 +685,7 @@ impl UnsafeCell { &self.value as *const T as *mut T } - /// Unwraps the value + /// Unwraps the value. /// /// # Unsafety /// diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 010415b364..740fa3eb19 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -139,6 +139,7 @@ pub fn from_digit(num: u32, radix: u32) -> Option { // NB: the stabilization and documentation for this trait is in // unicode/char.rs, not here #[allow(missing_docs)] // docs in libunicode/u_char.rs +#[doc(hidden)] pub trait CharExt { fn is_digit(self, radix: u32) -> bool; fn to_digit(self, radix: u32) -> Option; @@ -226,7 +227,7 @@ impl CharExt for char { #[inline] pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> Option { // Marked #[inline] to allow llvm optimizing it away - if code < MAX_ONE_B && dst.len() >= 1 { + if code < MAX_ONE_B && !dst.is_empty() { dst[0] = code as u8; Some(1) } else if code < MAX_TWO_B && dst.len() >= 2 { @@ -257,7 +258,7 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> Option { #[inline] pub fn encode_utf16_raw(mut ch: u32, dst: &mut [u16]) -> Option { // Marked #[inline] to allow llvm optimizing it away - if (ch & 0xFFFF) == ch && dst.len() >= 1 { + if (ch & 0xFFFF) == ch && !dst.is_empty() { // The BMP falls through (assuming non-surrogate, as it should) dst[0] = ch as u16; Some(1) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 85e5bde485..f11c01507d 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -38,14 +38,13 @@ pub trait Clone : Sized { #[stable(feature = "rust1", since = "1.0.0")] fn clone(&self) -> Self; - /// Perform copy-assignment from `source`. + /// Performs copy-assignment from `source`. /// /// `a.clone_from(&b)` is equivalent to `a = b.clone()` in functionality, /// but can be overridden to reuse the resources of `a` to avoid unnecessary /// allocations. #[inline(always)] - #[unstable(feature = "core", - reason = "this function is rarely used")] + #[stable(feature = "rust1", since = "1.0.0")] fn clone_from(&mut self, source: &Self) { *self = source.clone() } @@ -53,7 +52,7 @@ pub trait Clone : Sized { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: ?Sized> Clone for &'a T { - /// Return a shallow copy of the reference. + /// Returns a shallow copy of the reference. #[inline] fn clone(&self) -> &'a T { *self } } @@ -62,7 +61,7 @@ macro_rules! clone_impl { ($t:ty) => { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for $t { - /// Return a deep copy of the value. + /// Returns a deep copy of the value. #[inline] fn clone(&self) -> $t { *self } } @@ -93,10 +92,31 @@ macro_rules! extern_fn_clone { #[unstable(feature = "core", reason = "this may not be sufficient for fns with region parameters")] impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType { - /// Return a copy of a function pointer + /// Returns a copy of a function pointer. #[inline] fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self } } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for extern "C" fn($($A),*) -> ReturnType { + /// Returns a copy of a function pointer. + #[inline] + fn clone(&self) -> extern "C" fn($($A),*) -> ReturnType { *self } + } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for unsafe extern "Rust" fn($($A),*) -> ReturnType { + /// Returns a copy of a function pointer. + #[inline] + fn clone(&self) -> unsafe extern "Rust" fn($($A),*) -> ReturnType { *self } + } + + #[unstable(feature = "core", reason = "brand new")] + impl<$($A,)* ReturnType> Clone for unsafe extern "C" fn($($A),*) -> ReturnType { + /// Returns a copy of a function pointer. + #[inline] + fn clone(&self) -> unsafe extern "C" fn($($A),*) -> ReturnType { *self } + } ) } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index efe1179621..dd59ceff57 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -14,27 +14,6 @@ //! implement comparison operators. Rust programs may implement `PartialOrd` to overload the `<`, //! `<=`, `>`, and `>=` operators, and may implement `PartialEq` to overload the `==` and `!=` //! operators. -//! -//! For example, to define a type with a customized definition for the PartialEq operators, you -//! could do the following: -//! -//! ``` -//! # #![feature(core)] -//! struct FuzzyNum { -//! num: i32, -//! } -//! -//! impl PartialEq for FuzzyNum { -//! // Our custom eq allows numbers which are near each other to be equal! :D -//! fn eq(&self, other: &FuzzyNum) -> bool { -//! (self.num - other.num).abs() < 5 -//! } -//! } -//! -//! // Now these binary operators will work when applied! -//! assert!(FuzzyNum { num: 37 } == FuzzyNum { num: 34 }); -//! assert!(FuzzyNum { num: 25 } != FuzzyNum { num: 57 }); -//! ``` #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 4a99f1a756..1c1ad5fd33 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -10,18 +10,38 @@ //! Traits for conversions between types. //! -//! The traits in this module provide a general way to talk about -//! conversions from one type to another. They follow the standard -//! Rust conventions of `as`/`to`/`into`/`from`. +//! The traits in this module provide a general way to talk about conversions from one type to +//! another. They follow the standard Rust conventions of `as`/`to`/`into`/`from`. +//! +//! Like many traits, these are often used as bounds for generic functions, to support arguments of +//! multiple types. +//! +//! See each trait for usage examples. #![stable(feature = "rust1", since = "1.0.0")] use marker::Sized; /// A cheap, reference-to-reference conversion. +/// +/// # Examples +/// +/// Both `String` and `&str` implement `AsRef`: +/// +/// ``` +/// fn is_hello>(s: T) { +/// assert_eq!("hello", s.as_ref()); +/// } +/// +/// let s = "hello"; +/// is_hello(s); +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { - /// Perform the conversion. + /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] fn as_ref(&self) -> &T; } @@ -29,24 +49,50 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { - /// Perform the conversion. + /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be -/// expensive. +/// A conversion that consumes `self`, which may or may not be expensive. +/// +/// # Examples +/// +/// `String` implements `Into>`: +/// +/// ``` +/// fn is_hello>>(s: T) { +/// let bytes = b"hello".to_vec(); +/// assert_eq!(bytes, s.into()); +/// } +/// +/// let s = "hello".to_string(); +/// is_hello(s); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { - /// Perform the conversion. + /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] fn into(self) -> T; } /// Construct `Self` via a conversion. +/// +/// # Examples +/// +/// `String` implements `From<&str>`: +/// +/// ``` +/// let s = "hello"; +/// let string = "hello".to_string(); +/// +/// let other_string: String = From::from(s); +/// +/// assert_eq!(string, other_string); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait From { - /// Perform the conversion. + /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] fn from(T) -> Self; } diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 910cf805f3..f5103d394e 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -24,8 +24,6 @@ //! How can we define some default values? You can use `Default`: //! //! ``` -//! use std::default::Default; -//! //! #[derive(Default)] //! struct SomeOptions { //! foo: i32, @@ -42,8 +40,6 @@ //! If you have your own type, you need to implement `Default` yourself: //! //! ``` -//! use std::default::Default; -//! //! enum Kind { //! A, //! B, @@ -70,7 +66,6 @@ //! If you want to override a particular option, but still retain the other defaults: //! //! ``` -//! # use std::default::Default; //! # #[derive(Default)] //! # struct SomeOptions { //! # foo: i32, @@ -109,8 +104,6 @@ pub trait Default { /// Using built-in default values: /// /// ``` - /// use std::default::Default; - /// /// let i: i8 = Default::default(); /// let (x, y): (Option, f64) = Default::default(); /// let (a, b, (c, d)): (i32, u32, (bool, bool)) = Default::default(); @@ -119,8 +112,6 @@ pub trait Default { /// Making your own: /// /// ``` - /// use std::default::Default; - /// /// enum Kind { /// A, /// B, diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 6a5943265c..4b75bd5f67 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,22 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(missing_docs)] - pub use self::ExponentFormat::*; pub use self::SignificantDigits::*; -pub use self::SignFormat::*; + +use prelude::*; use char; -use char::CharExt; use fmt; -use iter::Iterator; -use num::{cast, Float, ToPrimitive}; +use num::Float; use num::FpCategory as Fp; -use ops::FnOnce; -use result::Result::Ok; -use slice::{self, SliceExt}; -use str::{self, StrExt}; +use ops::{Div, Rem, Mul}; +use slice; +use str; /// A flag that specifies whether to use exponential (scientific) notation. pub enum ExponentFormat { @@ -46,50 +42,44 @@ pub enum SignificantDigits { DigExact(usize) } -/// How to emit the sign of a number. -pub enum SignFormat { - /// `-` will be printed for negative values, but no sign will be emitted - /// for positive numbers. - SignNeg +#[doc(hidden)] +pub trait MyFloat: Float + PartialEq + PartialOrd + Div + + Mul + Rem + Copy { + fn from_u32(u: u32) -> Self; + fn to_i32(&self) -> i32; } -const DIGIT_E_RADIX: u32 = ('e' as u32) - ('a' as u32) + 11; +macro_rules! doit { + ($($t:ident)*) => ($(impl MyFloat for $t { + fn from_u32(u: u32) -> $t { u as $t } + fn to_i32(&self) -> i32 { *self as i32 } + })*) +} +doit! { f32 f64 } -/// Converts a number to its string representation as a byte vector. -/// This is meant to be a common base implementation for all numeric string -/// conversion functions like `to_string()` or `to_str_radix()`. +/// Converts a float number to its string representation. +/// This is meant to be a common base implementation for various formatting styles. +/// The number is assumed to be non-negative, callers use `Formatter::pad_integral` +/// to add the right sign, if any. /// /// # Arguments /// -/// - `num` - The number to convert. Accepts any number that +/// - `num` - The number to convert (non-negative). Accepts any number that /// implements the numeric traits. -/// - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation -/// is used, then this base is only used for the significand. The exponent -/// itself always printed using a base of 10. -/// - `negative_zero` - Whether to treat the special value `-0` as -/// `-0` or as `+0`. -/// - `sign` - How to emit the sign. See `SignFormat`. /// - `digits` - The amount of digits to use for emitting the fractional /// part, if any. See `SignificantDigits`. /// - `exp_format` - Whether or not to use the exponential (scientific) notation. /// See `ExponentFormat`. /// - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if /// exponential notation is desired. -/// - `f` - A closure to invoke with the bytes representing the +/// - `f` - A closure to invoke with the string representing the /// float. /// /// # Panics /// -/// - Panics if `radix` < 2 or `radix` > 36. -/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict -/// between digit and exponent sign `'e'`. -/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict -/// between digit and exponent sign `'p'`. -pub fn float_to_str_bytes_common( +/// - Panics if `num` is negative. +pub fn float_to_str_bytes_common( num: T, - radix: u32, - negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool, @@ -97,16 +87,12 @@ pub fn float_to_str_bytes_common( ) -> U where F: FnOnce(&str) -> U, { - assert!(2 <= radix && radix <= 36); - match exp_format { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - _ => () - } + let _0: T = T::zero(); + let _1: T = T::one(); + let radix: u32 = 10; + let radix_f = T::from_u32(radix); - let _0: T = Float::zero(); - let _1: T = Float::one(); + assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative"); match num.classify() { Fp::Nan => return f("NaN"), @@ -119,44 +105,31 @@ pub fn float_to_str_bytes_common( _ => {} } - let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); - // For an f64 the exponent is in the range of [-1022, 1023] for base 2, so - // we may have up to that many digits. Give ourselves some extra wiggle room - // otherwise as well. - let mut buf = [0; 1536]; + // For an f64 the (decimal) exponent is roughly in the range of [-307, 308], so + // we may have up to that many digits. We err on the side of caution and + // add 50% extra wiggle room. + let mut buf = [0; 462]; let mut end = 0; - let radix_gen: T = cast(radix as isize).unwrap(); let (num, exp) = match exp_format { - ExpNone => (num, 0), - ExpDec if num == _0 => (num, 0), - ExpDec => { - let (exp, exp_base) = match exp_format { - ExpDec => (num.abs().log10().floor(), cast::(10.0f64).unwrap()), - ExpNone => panic!("unreachable"), - }; - - (num / exp_base.powf(exp), cast::(exp).unwrap()) + ExpDec if num != _0 => { + let exp = num.log10().floor(); + (num / radix_f.powf(exp), exp.to_i32()) } + _ => (num, 0) }; // First emit the non-fractional part, looping at least once to make // sure at least a `0` gets emitted. let mut deccum = num.trunc(); loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit = (deccum % radix_gen).abs(); + let current_digit = deccum % radix_f; // Decrease the deccumulator one digit at a time - deccum = deccum / radix_gen; + deccum = deccum / radix_f; deccum = deccum.trunc(); - let c = char::from_digit(current_digit.to_isize().unwrap() as u32, radix); + let c = char::from_digit(current_digit.to_i32() as u32, radix); buf[end] = c.unwrap() as u8; end += 1; @@ -170,15 +143,6 @@ pub fn float_to_str_bytes_common( DigExact(count) => (true, count + 1, true) }; - // Decide what sign to put in front - match sign { - SignNeg if neg => { - buf[end] = b'-'; - end += 1; - } - _ => () - } - buf[..end].reverse(); // Remember start of the fractional digits. @@ -205,14 +169,11 @@ pub fn float_to_str_bytes_common( ) ) { // Shift first fractional digit into the integer part - deccum = deccum * radix_gen; + deccum = deccum * radix_f; - // Calculate the absolute value of each digit. - // See note in first loop. - let current_digit = deccum.trunc().abs(); + let current_digit = deccum.trunc(); - let c = char::from_digit(current_digit.to_isize().unwrap() as u32, - radix); + let c = char::from_digit(current_digit.to_i32() as u32, radix); buf[end] = c.unwrap() as u8; end += 1; @@ -242,7 +203,7 @@ pub fn float_to_str_bytes_common( if i < 0 || buf[i as usize] == b'-' || buf[i as usize] == b'+' { - for j in (i as usize + 1..end).rev() { + for j in ((i + 1) as usize..end).rev() { buf[j + 1] = buf[j]; } buf[(i + 1) as usize] = value2ascii(1); @@ -301,12 +262,8 @@ pub fn float_to_str_bytes_common( match exp_format { ExpNone => {}, - _ => { - buf[end] = match exp_format { - ExpDec if exp_upper => 'E', - ExpDec if !exp_upper => 'e', - _ => panic!("unreachable"), - } as u8; + ExpDec => { + buf[end] = if exp_upper { b'E' } else { b'e' }; end += 1; struct Filler<'a> { @@ -324,11 +281,7 @@ pub fn float_to_str_bytes_common( } let mut filler = Filler { buf: &mut buf, end: &mut end }; - match sign { - SignNeg => { - let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); - } - } + let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); } } diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index be80432766..5cff0186f2 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,20 +12,16 @@ #![stable(feature = "rust1", since = "1.0.0")] +use prelude::*; + use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; -use char::CharExt; -use clone::Clone; -use iter::Iterator; -use marker::{Copy, PhantomData, Sized}; +use marker::PhantomData; use mem; -use option::Option; -use option::Option::{Some, None}; -use result::Result::Ok; -use ops::{Deref, FnOnce}; +use ops::Deref; use result; -use slice::SliceExt; +use num::Float; use slice; -use str::{self, StrExt}; +use str; use self::rt::v1::Alignment; pub use self::num::radix; @@ -38,7 +34,8 @@ mod num; mod float; mod builders; -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[doc(hidden)] pub mod rt { pub mod v1; @@ -134,7 +131,8 @@ enum Void {} /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. #[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[doc(hidden)] pub struct ArgumentV1<'a> { value: &'a Void, @@ -154,7 +152,8 @@ impl<'a> ArgumentV1<'a> { } #[doc(hidden)] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> { unsafe { @@ -166,7 +165,8 @@ impl<'a> ArgumentV1<'a> { } #[doc(hidden)] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn from_usize(x: &usize) -> ArgumentV1 { ArgumentV1::new(x, ArgumentV1::show_usize) } @@ -189,7 +189,8 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. #[doc(hidden)] #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new_v1(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { Arguments { @@ -206,7 +207,8 @@ impl<'a> Arguments<'a> { /// created with `argumentusize`. However, failing to do so doesn't cause /// unsafety, but will ignore invalid . #[doc(hidden)] #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new_v1_formatted(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument]) -> Arguments<'a> { @@ -847,9 +849,32 @@ impl Display for char { #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for *const T { fn fmt(&self, f: &mut Formatter) -> Result { + let old_width = f.width; + let old_flags = f.flags; + + // The alternate flag is already treated by LowerHex as being special- + // it denotes whether to prefix with 0x. We use it to work out whether + // or not to zero extend, and then unconditionally set it to get the + // prefix. + if f.flags & 1 << (FlagV1::Alternate as u32) > 0 { + f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); + + if let None = f.width { + // The formats need two extra bytes, for the 0x + if cfg!(target_pointer_width = "32") { + f.width = Some(10); + } else { + f.width = Some(18); + } + } + } f.flags |= 1 << (FlagV1::Alternate as u32); + let ret = LowerHex::fmt(&(*self as usize), f); - f.flags &= !(1 << (FlagV1::Alternate as u32)); + + f.width = old_width; + f.flags = old_flags; + ret } } @@ -881,33 +906,39 @@ impl<'a, T> Pointer for &'a mut T { } } +// Common code of floating point Debug and Display. +fn float_to_str_common(num: &T, precision: Option, + post: F) -> Result + where F : FnOnce(&str) -> Result { + let digits = match precision { + Some(i) => float::DigExact(i), + None => float::DigMax(6), + }; + float::float_to_str_bytes_common(num.abs(), + digits, + float::ExpNone, + false, + post) +} + macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - Display::fmt(self, fmt) + float_to_str_common(self, fmt.precision, |absolute| { + // is_positive() counts -0.0 as negative + fmt.pad_integral(self.is_nan() || self.is_positive(), "", absolute) + }) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - use num::Float; - - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, - digits, - float::ExpNone, - false, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) + float_to_str_common(self, fmt.precision, |absolute| { + // simple comparison counts -0.0 as positive + fmt.pad_integral(self.is_nan() || *self >= 0.0, "", absolute) }) } } @@ -915,16 +946,11 @@ macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl LowerExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - use num::Float; - let digits = match fmt.precision { Some(i) => float::DigExact(i), None => float::DigMax(6), }; float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, digits, float::ExpDec, false, @@ -937,16 +963,11 @@ macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl UpperExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - use num::Float; - let digits = match fmt.precision { Some(i) => float::DigExact(i), None => float::DigMax(6), }; float::float_to_str_bytes_common(self.abs(), - 10, - true, - float::SignNeg, digits, float::ExpDec, true, diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 76c975902a..122fffc595 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -14,12 +14,28 @@ #![allow(unsigned_negation)] +use prelude::*; + use fmt; -use iter::Iterator; -use num::{Int, cast}; -use slice::SliceExt; +use num::Zero; +use ops::{Div, Rem, Sub}; use str; +#[doc(hidden)] +trait Int: Zero + PartialEq + PartialOrd + Div + Rem + + Sub + Copy { + fn from_u8(u: u8) -> Self; + fn to_u8(&self) -> u8; +} + +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 } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + /// A type that represents a specific radix #[doc(hidden)] trait GenericRadix { @@ -33,33 +49,32 @@ trait GenericRadix { fn digit(&self, x: u8) -> u8; /// Format an integer using the radix using a formatter. - #[allow(deprecated)] // Int fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { // The radix can be as low as 2, so we need a buffer of at least 64 // characters for a base 2 number. - let zero = Int::zero(); + let zero = T::zero(); let is_positive = x >= zero; let mut buf = [0; 64]; let mut curr = buf.len(); - let base = cast(self.base()).unwrap(); + let base = T::from_u8(self.base()); if is_positive { // Accumulate each digit of the number from the least significant // to the most significant figure. for byte in buf.iter_mut().rev() { - let n = x % base; // Get the current place value. - x = x / base; // Deaccumulate the number. - *byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer. + let n = x % base; // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = self.digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; - if x == zero { break }; // No more digits left to accumulate. + if x == zero { break }; // No more digits left to accumulate. } } else { // Do the same as above, but accounting for two's complement. for byte in buf.iter_mut().rev() { - let n = zero - (x % base); // Get the current place value. - x = x / base; // Deaccumulate the number. - *byte = self.digit(cast(n).unwrap()); // Store the digit in the buffer. + let n = zero - (x % base); // Get the current place value. + x = x / base; // Deaccumulate the number. + *byte = self.digit(n.to_u8()); // Store the digit in the buffer. curr -= 1; - if x == zero { break }; // No more digits left to accumulate. + if x == zero { break }; // No more digits left to accumulate. } } let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) }; diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs index d56ec6a74d..0d851c1e89 100644 --- a/src/libcore/fmt/rt/v1.rs +++ b/src/libcore/fmt/rt/v1.rs @@ -14,68 +14,69 @@ //! These definitions are similar to their `ct` equivalents, but differ in that //! these can be statically allocated and are slightly optimized for the runtime -#![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#![cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub struct Argument { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub position: Position, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub format: FormatSpec, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub struct FormatSpec { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub fill: char, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub align: Alignment, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub flags: u32, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub precision: Count, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub width: Count, } /// Possible alignments that can be requested as part of a formatting directive. #[derive(Copy, Clone, PartialEq)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Alignment { /// Indication that contents should be left-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Left, /// Indication that contents should be right-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Right, /// Indication that contents should be center-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Center, /// No alignment was requested. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Unknown, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Count { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Is(usize), - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Param(usize), - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] NextParam, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Implied, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Position { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Next, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] At(usize) } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 2375ae8965..e848a44e01 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -62,7 +62,6 @@ use prelude::*; -use default::Default; use mem; pub use self::sip::SipHasher; @@ -194,7 +193,7 @@ mod impls { fn hash_slice(data: &[$ty], state: &mut H) { // FIXME(#23542) Replace with type ascription. #![allow(trivial_casts)] - let newlen = data.len() * ::$ty::BYTES as usize; + let newlen = data.len() * ::$ty::BYTES; let ptr = data.as_ptr() as *const u8; state.write(unsafe { slice::from_raw_parts(ptr, newlen) }) } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 6820a7025f..0bff9b0ba4 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -15,7 +15,6 @@ #![allow(deprecated)] // until the next snapshot for inherent wrapping ops use prelude::*; -use default::Default; use super::Hasher; /// An implementation of SipHash 2-4. diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 0e91eafce1..8ed89adec5 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -139,16 +139,16 @@ extern "rust-intrinsic" { pub fn atomic_fence_rel(); pub fn atomic_fence_acqrel(); - /// Abort the execution of the process. + /// Aborts the execution of the process. pub fn abort() -> !; - /// Tell LLVM that this point in the code is not reachable, + /// Tells LLVM that this point in the code is not reachable, /// enabling further optimizations. /// /// NB: This is very different from the `unreachable!()` macro! pub fn unreachable() -> !; - /// Inform the optimizer that a condition is always true. + /// Informs the optimizer that a condition is always true. /// If the condition is false, the behavior is undefined. /// /// No code is generated for this intrinsic, but the optimizer will try @@ -158,7 +158,7 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. pub fn assume(b: bool); - /// Execute a breakpoint trap, for inspection by a debugger. + /// Executes a breakpoint trap, for inspection by a debugger. pub fn breakpoint(); /// The size of a type in bytes. @@ -170,7 +170,7 @@ extern "rust-intrinsic" { /// elements. pub fn size_of() -> usize; - /// Move a value to an uninitialized memory location. + /// 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); @@ -186,7 +186,7 @@ extern "rust-intrinsic" { /// crate it is invoked in. pub fn type_id() -> u64; - /// Create a value initialized to so that its drop flag, + /// Creates a value initialized to so that its drop flag, /// if any, says that it has been dropped. /// /// `init_dropped` is unsafe because it returns a datum with all @@ -199,7 +199,7 @@ extern "rust-intrinsic" { /// intrinsic). pub fn init_dropped() -> T; - /// Create a value initialized to zero. + /// Creates a value initialized to zero. /// /// `init` is unsafe because it returns a zeroed-out datum, /// which is unsafe unless T is `Copy`. Also, even if T is @@ -207,7 +207,7 @@ extern "rust-intrinsic" { /// state for the type in question. pub fn init() -> T; - /// Create an uninitialized value. + /// Creates an uninitialized value. /// /// `uninit` is unsafe because there is no guarantee of what its /// contents are. In particular its drop-flag may be set to any @@ -216,7 +216,7 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Move a value out of scope without running drop glue. + /// Moves a value out of scope without running drop glue. /// /// `forget` is unsafe because the caller is responsible for /// ensuring the argument is deallocated already. @@ -569,4 +569,10 @@ extern "rust-intrinsic" { pub fn overflowing_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2^N, where N is the width of N in bits. pub fn overflowing_mul(a: T, b: T) -> T; + + /// Returns the value of the discriminant for the variant in 'v', + /// cast to a `u64`; if `T` has no discriminant, returns 0. + // SNAP 5520801 + #[cfg(not(stage0))] + pub fn discriminant_value(v: &T) -> u64; } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 42e90ec34d..233ed01811 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -60,17 +60,17 @@ use self::MinMaxResult::*; use clone::Clone; use cmp; -use cmp::Ord; +use cmp::{Ord, PartialOrd, PartialEq}; use default::Default; use marker; use mem; -use num::{Int, Zero, One}; -use ops::{self, Add, Sub, FnMut, RangeFrom}; +use num::{Zero, One}; +use ops::{self, Add, Sub, FnMut, Mul, RangeFrom}; use option::Option::{self, Some, None}; use marker::Sized; use usize; -fn _assert_is_object_safe(_: &Iterator) {} +fn _assert_is_object_safe(_: &Iterator) {} /// An interface for dealing with "external iterators". These types of iterators /// can be resumed at any time as all state is stored internally as opposed to @@ -91,7 +91,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] type Item; - /// Advance the iterator and return the next value. Return `None` when the + /// Advances the iterator and returns the next value. Returns `None` when the /// end is reached. #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; @@ -171,16 +171,16 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn chain(self, other: U) -> Chain where - Self: Sized, U: Iterator, + fn chain(self, other: U) -> Chain where + Self: Sized, U: IntoIterator, { - Chain{a: self, b: other, flag: false} + Chain{a: self, b: other.into_iter(), flag: false} } /// Creates an iterator that iterates over both this and the specified /// iterators simultaneously, yielding the two elements as pairs. When - /// either iterator returns None, all further invocations of next() will - /// return None. + /// either iterator returns `None`, all further invocations of next() will + /// return `None`. /// /// # Examples /// @@ -207,8 +207,10 @@ pub trait Iterator { /// both produce the same output. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn zip(self, other: U) -> Zip where Self: Sized { - Zip{a: self, b: other} + fn zip(self, other: U) -> Zip where + Self: Sized, U: IntoIterator + { + Zip{a: self, b: other.into_iter()} } /// Creates a new iterator that will apply the specified function to each @@ -252,7 +254,7 @@ pub trait Iterator { } /// Creates an iterator that both filters and maps elements. - /// If the specified function returns None, the element is skipped. + /// If the specified function returns `None`, the element is skipped. /// Otherwise the option is unwrapped and the new value is yielded. /// /// # Examples @@ -271,8 +273,9 @@ pub trait Iterator { FilterMap { iter: self, f: f } } - /// Creates an iterator that yields a pair of the value returned by this - /// iterator plus the current index of iteration. + /// Creates an iterator that yields pairs `(i, val)` where `i` is the + /// current index of iteration and `val` is the value returned by the + /// iterator. /// /// `enumerate` keeps its count as a `usize`. If you want to count by a /// different sized integer, the `zip` function provides similar @@ -400,7 +403,7 @@ pub trait Iterator { /// Creates a new iterator that behaves in a similar fashion to fold. /// There is a state which is passed between each iteration and can be /// mutated as necessary. The yielded values from the closure are yielded - /// from the Scan instance when not None. + /// from the Scan instance when not `None`. /// /// # Examples /// @@ -443,7 +446,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn flat_map(self, f: F) -> FlatMap - where Self: Sized, U: Iterator, F: FnMut(Self::Item) -> U, + where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U, { FlatMap{iter: self, f: f, frontiter: None, backiter: None } } @@ -489,15 +492,14 @@ pub trait Iterator { /// /// ``` /// # #![feature(core)] - /// use std::iter::AdditiveIterator; /// /// let a = [1, 4, 2, 3, 8, 9, 6]; - /// let sum = a.iter() - /// .map(|x| *x) - /// .inspect(|&x| println!("filtering {}", x)) - /// .filter(|&x| x % 2 == 0) - /// .inspect(|&x| println!("{} made it through", x)) - /// .sum(); + /// let sum: i32 = a.iter() + /// .map(|x| *x) + /// .inspect(|&x| println!("filtering {}", x)) + /// .filter(|&x| x % 2 == 0) + /// .inspect(|&x| println!("{} made it through", x)) + /// .sum(); /// println!("{}", sum); /// ``` #[inline] @@ -608,7 +610,11 @@ pub trait Iterator { fn all(&mut self, mut f: F) -> bool where Self: Sized, F: FnMut(Self::Item) -> bool { - for x in self.by_ref() { if !f(x) { return false; } } + for x in self.by_ref() { + if !f(x) { + return false; + } + } true } @@ -633,7 +639,11 @@ pub trait Iterator { Self: Sized, F: FnMut(Self::Item) -> bool { - for x in self.by_ref() { if f(x) { return true; } } + for x in self.by_ref() { + if f(x) { + return true; + } + } false } @@ -661,7 +671,7 @@ pub trait Iterator { None } - /// Return the index of the first element satisfying the specified predicate + /// Returns the index of the first element satisfying the specified predicate /// /// Does not consume the iterator past the first found element. /// @@ -689,9 +699,9 @@ pub trait Iterator { None } - /// Return the index of the last element satisfying the specified predicate + /// Returns the index of the last element satisfying the specified predicate /// - /// If no element matches, None is returned. + /// If no element matches, `None` is returned. /// /// Does not consume the iterator *before* the first found element. /// @@ -735,12 +745,12 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn max(self) -> Option where Self: Sized, Self::Item: Ord { - self.fold(None, |max, y| { - match max { - None => Some(y), - Some(x) => Some(cmp::max(x, y)) - } - }) + select_fold1(self, + |_| (), + // switch to y even if it is only equal, to preserve + // stability. + |_, x, _, y| *x <= *y) + .map(|(_, x)| x) } /// Consumes the entire iterator to return the minimum element. @@ -758,12 +768,12 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] fn min(self) -> Option where Self: Sized, Self::Item: Ord { - self.fold(None, |min, y| { - match min { - None => Some(y), - Some(x) => Some(cmp::min(x, y)) - } - }) + select_fold1(self, + |_| (), + // only switch to y if it is strictly smaller, to + // preserve stability. + |_, x, _, y| *x > *y) + .map(|(_, x)| x) } /// `min_max` finds the minimum and maximum elements in the iterator. @@ -844,7 +854,7 @@ pub trait Iterator { MinMax(min, max) } - /// Return the element that gives the maximum value from the + /// Returns the element that gives the maximum value from the /// specified function. /// /// Returns the rightmost element if the comparison determines two elements @@ -861,24 +871,19 @@ pub trait Iterator { #[inline] #[unstable(feature = "core", reason = "may want to produce an Ordering directly; see #15311")] - fn max_by(self, mut f: F) -> Option where + fn max_by(self, f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - self.fold(None, |max: Option<(Self::Item, B)>, y| { - let y_val = f(&y); - match max { - None => Some((y, y_val)), - Some((x, x_val)) => if y_val >= x_val { - Some((y, y_val)) - } else { - Some((x, x_val)) - } - } - }).map(|(x, _)| x) + select_fold1(self, + f, + // switch to y even if it is only equal, to preserve + // stability. + |x_p, _, y_p, _| x_p <= y_p) + .map(|(_, x)| x) } - /// Return the element that gives the minimum value from the + /// Returns the element that gives the minimum value from the /// specified function. /// /// Returns the leftmost element if the comparison determines two elements @@ -895,21 +900,16 @@ pub trait Iterator { #[inline] #[unstable(feature = "core", reason = "may want to produce an Ordering directly; see #15311")] - fn min_by(self, mut f: F) -> Option where + fn min_by(self, f: F) -> Option where Self: Sized, F: FnMut(&Self::Item) -> B, { - self.fold(None, |min: Option<(Self::Item, B)>, y| { - let y_val = f(&y); - match min { - None => Some((y, y_val)), - Some((x, x_val)) => if x_val <= y_val { - Some((x, x_val)) - } else { - Some((y, y_val)) - } - } - }).map(|(x, _)| x) + select_fold1(self, + f, + // only switch to y if it is strictly smaller, to + // preserve stability. + |x_p, _, y_p, _| x_p > y_p) + .map(|(_, x)| x) } /// Change the direction of the iterator @@ -926,7 +926,7 @@ pub trait Iterator { /// `std::usize::MAX` elements of the original iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn rev(self) -> Rev where Self: Sized { + fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator { Rev{iter: self} } @@ -1014,6 +1014,78 @@ pub trait Iterator { } } } + + /// Iterates over the entire iterator, summing up all the elements + /// + /// # Examples + /// + /// ``` + /// # #![feature(core)] + /// + /// let a = [1, 2, 3, 4, 5]; + /// let mut it = a.iter().cloned(); + /// assert!(it.sum::() == 15); + /// ``` + #[unstable(feature="core")] + fn sum::Item>(self) -> S where + S: Add + Zero, + Self: Sized, + { + self.fold(Zero::zero(), |s, e| s + e) + } + + /// Iterates over the entire iterator, multiplying all the elements + /// + /// # Examples + /// + /// ``` + /// # #![feature(core)] + /// + /// fn factorial(n: u32) -> u32 { + /// (1..).take_while(|&i| i <= n).product() + /// } + /// assert!(factorial(0) == 1); + /// assert!(factorial(1) == 1); + /// assert!(factorial(5) == 120); + /// ``` + #[unstable(feature="core")] + fn product::Item>(self) -> P where + P: Mul + One, + Self: Sized, + { + self.fold(One::one(), |p, e| p * e) + } +} + +/// Select an element from an iterator based on the given projection +/// and "comparison" function. +/// +/// This is an idiosyncratic helper to try to factor out the +/// commonalities of {max,min}{,_by}. In particular, this avoids +/// having to implement optimisations several times. +#[inline] +fn select_fold1(mut it: I, + mut f_proj: FProj, + mut f_cmp: FCmp) -> Option<(B, I::Item)> + where I: Iterator, + FProj: FnMut(&I::Item) -> B, + FCmp: FnMut(&B, &I::Item, &B, &I::Item) -> bool +{ + // start with the first element as our selection. This avoids + // having to use `Option`s inside the loop, translating to a + // sizeable performance gain (6x in one case). + it.next().map(|mut sel| { + let mut sel_p = f_proj(&sel); + + for x in it { + let x_p = f_proj(&x); + if f_cmp(&sel_p, &sel, &x_p, &x) { + sel = x; + sel_p = x_p; + } + } + (sel_p, sel) + }) } #[stable(feature = "rust1", since = "1.0.0")] @@ -1028,7 +1100,7 @@ impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I { #[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ built from an iterator over elements of type `{A}`"] pub trait FromIterator { - /// Build a container with elements from something iterable. + /// Builds a container with elements from something iterable. /// /// # Examples /// @@ -1058,14 +1130,14 @@ pub trait FromIterator { /// Conversion into an `Iterator` /// /// Implementing this trait allows you to use your type with Rust's `for` loop. See -/// the [module level documentation](../index.html) for more details. +/// the [module level documentation](index.html) for more details. #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated #[stable(feature = "rust1", since = "1.0.0")] type Item; - /// A container for iterating over elements of type Item + /// A container for iterating over elements of type `Item` #[stable(feature = "rust1", since = "1.0.0")] type IntoIter: Iterator; @@ -1087,7 +1159,7 @@ impl IntoIterator for I { /// A type growable from an `Iterator` implementation #[stable(feature = "rust1", since = "1.0.0")] pub trait Extend { - /// Extend a container with the elements yielded by an arbitrary iterator + /// Extends a container with the elements yielded by an arbitrary iterator #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iterable: T); } @@ -1099,7 +1171,7 @@ pub trait Extend { /// independently of each other. #[stable(feature = "rust1", since = "1.0.0")] pub trait DoubleEndedIterator: Iterator { - /// Yield an element from the end of the range, returning `None` if the + /// Yields an element from the end of the range, returning `None` if the /// range is empty. #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; @@ -1120,11 +1192,11 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { reason = "not widely used, may be better decomposed into Index \ and ExactSizeIterator")] pub trait RandomAccessIterator: Iterator { - /// Return the number of indexable elements. At most `std::usize::MAX` + /// Returns the number of indexable elements. At most `std::usize::MAX` /// elements are indexable, even if the iterator represents a longer range. fn indexable(&self) -> usize; - /// Return an element at an index, or `None` if the index is out of bounds + /// Returns an element at an index, or `None` if the index is out of bounds fn idx(&mut self, index: usize) -> Option; } @@ -1139,7 +1211,7 @@ pub trait RandomAccessIterator: Iterator { pub trait ExactSizeIterator: Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] - /// Return the exact length of the iterator. + /// Returns the exact length of the iterator. fn len(&self) -> usize { let (lower, upper) = self.size_hint(); // Note: This assertion is overly defensive, but it checks the invariant @@ -1214,95 +1286,6 @@ impl RandomAccessIterator for Rev } } -/// A trait for iterators over elements which can be added together -#[unstable(feature = "core", - reason = "needs to be re-evaluated as part of numerics reform")] -pub trait AdditiveIterator { - /// Iterates over the entire iterator, summing up all the elements - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::iter::AdditiveIterator; - /// - /// let a = [1, 2, 3, 4, 5]; - /// let mut it = a.iter().cloned(); - /// assert!(it.sum() == 15); - /// ``` - fn sum(self) -> A; -} - -macro_rules! impl_additive { - ($A:ty, $init:expr) => { - #[unstable(feature = "core", reason = "trait is experimental")] - impl> AdditiveIterator<$A> for T { - #[inline] - fn sum(self) -> $A { - self.fold($init, |acc, x| acc + x) - } - } - }; -} -impl_additive! { i8, 0 } -impl_additive! { i16, 0 } -impl_additive! { i32, 0 } -impl_additive! { i64, 0 } -impl_additive! { isize, 0 } -impl_additive! { u8, 0 } -impl_additive! { u16, 0 } -impl_additive! { u32, 0 } -impl_additive! { u64, 0 } -impl_additive! { usize, 0 } -impl_additive! { f32, 0.0 } -impl_additive! { f64, 0.0 } - -/// A trait for iterators over elements which can be multiplied together. -#[unstable(feature = "core", - reason = "needs to be re-evaluated as part of numerics reform")] -pub trait MultiplicativeIterator { - /// Iterates over the entire iterator, multiplying all the elements - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::iter::MultiplicativeIterator; - /// - /// fn factorial(n: usize) -> usize { - /// (1..).take_while(|&i| i <= n).product() - /// } - /// assert!(factorial(0) == 1); - /// assert!(factorial(1) == 1); - /// assert!(factorial(5) == 120); - /// ``` - fn product(self) -> A; -} - -macro_rules! impl_multiplicative { - ($A:ty, $init:expr) => { - #[unstable(feature = "core", reason = "trait is experimental")] - impl> MultiplicativeIterator<$A> for T { - #[inline] - fn product(self) -> $A { - self.fold($init, |acc, x| acc * x) - } - } - }; -} -impl_multiplicative! { i8, 1 } -impl_multiplicative! { i16, 1 } -impl_multiplicative! { i32, 1 } -impl_multiplicative! { i64, 1 } -impl_multiplicative! { isize, 1 } -impl_multiplicative! { u8, 1 } -impl_multiplicative! { u16, 1 } -impl_multiplicative! { u32, 1 } -impl_multiplicative! { u64, 1 } -impl_multiplicative! { usize, 1 } -impl_multiplicative! { f32, 1.0 } -impl_multiplicative! { f64, 1.0 } - /// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for /// more detail. #[derive(Clone, PartialEq, Debug)] @@ -1562,13 +1545,11 @@ impl Iterator for Zip where A: Iterator, B: Iterator #[inline] fn next(&mut self) -> Option<(A::Item, B::Item)> { - match self.a.next() { - None => None, - Some(x) => match self.b.next() { - None => None, - Some(y) => Some((x, y)) - } - } + self.a.next().and_then(|x| { + self.b.next().and_then(|y| { + Some((x, y)) + }) + }) } #[inline] @@ -1626,13 +1607,11 @@ impl RandomAccessIterator for Zip where #[inline] fn idx(&mut self, index: usize) -> Option<(A::Item, B::Item)> { - match self.a.idx(index) { - None => None, - Some(x) => match self.b.idx(index) { - None => None, - Some(y) => Some((x, y)) - } - } + self.a.idx(index).and_then(|x| { + self.b.idx(index).and_then(|y| { + Some((x, y)) + }) + }) } } @@ -1748,9 +1727,8 @@ impl Iterator for FilterMap #[inline] fn next(&mut self) -> Option { for x in self.iter.by_ref() { - match (self.f)(x) { - Some(y) => return Some(y), - None => () + if let Some(y) = (self.f)(x) { + return Some(y); } } None @@ -1770,9 +1748,8 @@ impl DoubleEndedIterator for FilterMap #[inline] fn next_back(&mut self) -> Option { for x in self.iter.by_ref().rev() { - match (self.f)(x) { - Some(y) => return Some(y), - None => () + if let Some(y) = (self.f)(x) { + return Some(y); } } None @@ -1794,14 +1771,11 @@ impl Iterator for Enumerate where I: Iterator { #[inline] fn next(&mut self) -> Option<(usize, ::Item)> { - match self.iter.next() { - Some(a) => { - let ret = Some((self.count, a)); - self.count += 1; - ret - } - _ => None - } + self.iter.next().map(|a| { + let ret = (self.count, a); + self.count += 1; + ret + }) } #[inline] @@ -1816,13 +1790,10 @@ impl DoubleEndedIterator for Enumerate where { #[inline] fn next_back(&mut self) -> Option<(usize, ::Item)> { - match self.iter.next_back() { - Some(a) => { - let len = self.iter.len(); - Some((self.count + len, a)) - } - _ => None - } + self.iter.next_back().map(|a| { + let len = self.iter.len(); + (self.count + len, a) + }) } } @@ -1835,10 +1806,7 @@ impl RandomAccessIterator for Enumerate where I: RandomAccessIterator { #[inline] fn idx(&mut self, index: usize) -> Option<(usize, ::Item)> { - match self.iter.idx(index) { - Some(a) => Some((self.count + index, a)), - _ => None, - } + self.iter.idx(index).map(|a| (self.count + index, a)) } } @@ -1865,8 +1833,10 @@ impl Iterator for Peekable { #[inline] fn next(&mut self) -> Option { - if self.peeked.is_some() { self.peeked.take() } - else { self.iter.next() } + match self.peeked { + Some(_) => self.peeked.take(), + None => self.iter.next(), + } } #[inline] @@ -1874,10 +1844,7 @@ impl Iterator for Peekable { let (lo, hi) = self.iter.size_hint(); if self.peeked.is_some() { let lo = lo.saturating_add(1); - let hi = match hi { - Some(x) => x.checked_add(1), - None => None - }; + let hi = hi.and_then(|x| x.checked_add(1)); (lo, hi) } else { (lo, hi) @@ -1890,7 +1857,7 @@ impl ExactSizeIterator for Peekable {} #[stable(feature = "rust1", since = "1.0.0")] impl Peekable { - /// Return a reference to the next element of the iterator with out + /// Returns a reference to the next element of the iterator with out /// advancing it, or None if the iterator is exhausted. #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1904,7 +1871,7 @@ impl Peekable { } } - /// Check whether peekable iterator is empty or not. + /// Checks whether peekable iterator is empty or not. #[inline] pub fn is_empty(&mut self) -> bool { self.peek().is_none() @@ -1966,17 +1933,14 @@ impl Iterator for TakeWhile if self.flag { None } else { - match self.iter.next() { - Some(x) => { - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } + self.iter.next().and_then(|x| { + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + None } - None => None - } + }) } } @@ -2030,11 +1994,7 @@ impl Iterator for Skip where I: Iterator { let (lower, upper) = self.iter.size_hint(); let lower = lower.saturating_sub(self.n); - - let upper = match upper { - Some(x) => Some(x.saturating_sub(self.n)), - None => None - }; + let upper = upper.map(|x| x.saturating_sub(self.n)); (lower, upper) } @@ -2157,15 +2117,15 @@ impl Iterator for Scan where #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] -pub struct FlatMap { +pub struct FlatMap { iter: I, f: F, - frontiter: Option, - backiter: Option, + frontiter: Option, + backiter: Option, } #[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FlatMap +impl Iterator for FlatMap where F: FnMut(I::Item) -> U, { type Item = U::Item; @@ -2174,13 +2134,13 @@ impl Iterator for FlatMap fn next(&mut self) -> Option { loop { if let Some(ref mut inner) = self.frontiter { - for x in inner.by_ref() { + if let Some(x) = inner.by_ref().next() { return Some(x) } } match self.iter.next().map(|x| (self.f)(x)) { None => return self.backiter.as_mut().and_then(|it| it.next()), - next => self.frontiter = next, + next => self.frontiter = next.map(IntoIterator::into_iter), } } } @@ -2198,22 +2158,22 @@ impl Iterator for FlatMap } #[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator - for FlatMap - where F: FnMut(I::Item) -> U +impl DoubleEndedIterator for FlatMap where + F: FnMut(I::Item) -> U, + U: IntoIterator, + U::IntoIter: DoubleEndedIterator { #[inline] fn next_back(&mut self) -> Option { loop { if let Some(ref mut inner) = self.backiter { - match inner.next_back() { - None => (), - y => return y + if let Some(y) = inner.next_back() { + return Some(y) } } match self.iter.next_back().map(|x| (self.f)(x)) { None => return self.frontiter.as_mut().and_then(|it| it.next_back()), - next => self.backiter = next, + next => self.backiter = next.map(IntoIterator::into_iter), } } } @@ -2238,13 +2198,9 @@ impl Iterator for Fuse where I: Iterator { if self.done { None } else { - match self.iter.next() { - None => { - self.done = true; - None - } - x => x - } + let next = self.iter.next(); + self.done = next.is_none(); + next } } @@ -2265,13 +2221,9 @@ impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { if self.done { None } else { - match self.iter.next_back() { - None => { - self.done = true; - None - } - x => x - } + let next = self.iter.next_back(); + self.done = next.is_none(); + next } } } @@ -2294,8 +2246,9 @@ impl RandomAccessIterator for Fuse where I: RandomAccessIterator { impl ExactSizeIterator for Fuse where I: ExactSizeIterator {} impl Fuse { - /// Resets the fuse such that the next call to .next() or .next_back() will - /// call the underlying iterator again even if it previously returned None. + /// Resets the `Fuse` such that the next call to `.next()` or + /// `.next_back()` will call the underlying iterator again even if it + /// previously returned `None`. #[inline] #[unstable(feature = "core", reason = "seems marginal")] pub fn reset_fuse(&mut self) { @@ -2316,9 +2269,8 @@ pub struct Inspect { impl Inspect where F: FnMut(&I::Item) { #[inline] fn do_inspect(&mut self, elt: Option) -> Option { - match elt { - Some(ref a) => (self.f)(a), - None => () + if let Some(ref a) = elt { + (self.f)(a); } elt @@ -2375,9 +2327,8 @@ impl RandomAccessIterator for Inspect /// An iterator that yields sequential Fibonacci numbers, and stops on overflow. /// /// ``` -/// # #![feature(core)] +/// #![feature(core)] /// use std::iter::Unfold; -/// use std::num::Int; // For `.checked_add()` /// /// // This iterator will yield up to the last Fibonacci number before the max /// // value of `u32`. You can simply change `u32` to `u64` in this line if @@ -2447,16 +2398,16 @@ impl Iterator for Unfold where F: FnMut(&mut St) -> Option { /// two `Step` objects. #[unstable(feature = "step_trait", reason = "likely to be replaced by finer-grained traits")] -pub trait Step: Ord { +pub trait Step: PartialOrd { /// Steps `self` if possible. fn step(&self, by: &Self) -> Option; - /// The number of steps between two step objects. + /// Returns the number of steps between two step objects. /// /// `start` should always be less than `end`, so the result should never /// be negative. /// - /// Return `None` if it is not possible to calculate steps_between + /// Returns `None` if it is not possible to calculate steps_between /// without overflow. fn steps_between(start: &Self, end: &Self, by: &Self) -> Option; } @@ -2599,7 +2550,7 @@ pub struct RangeInclusive { done: bool, } -/// Return an iterator over the range [start, stop] +/// Returns an iterator over the range [start, stop]. #[inline] #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] @@ -2614,22 +2565,22 @@ pub fn range_inclusive(start: A, stop: A) -> RangeInclusive #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] -impl Iterator for RangeInclusive { +impl Iterator for RangeInclusive where + A: PartialEq + Step + One + Clone, + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] fn next(&mut self) -> Option { - match self.range.next() { - Some(x) => Some(x), - None => { - if !self.done && self.range.start == self.range.end { - self.done = true; - Some(self.range.end.clone()) - } else { - None - } + self.range.next().or_else(|| { + if !self.done && self.range.start == self.range.end { + self.done = true; + Some(self.range.end.clone()) + } else { + None } - } + }) } #[inline] @@ -2639,10 +2590,7 @@ impl Iterator for RangeInclusive { (lo, hi) } else { let lo = lo.saturating_add(1); - let hi = match hi { - Some(x) => x.checked_add(1), - None => None - }; + let hi = hi.and_then(|x| x.checked_add(1)); (lo, hi) } } @@ -2650,9 +2598,10 @@ impl Iterator for RangeInclusive { #[unstable(feature = "core", reason = "likely to be replaced by range notation and adapters")] -impl DoubleEndedIterator for RangeInclusive - where A: Step + One + Clone, - for<'a> &'a A: Sub +impl DoubleEndedIterator for RangeInclusive where + A: PartialEq + Step + One + Clone, + for<'a> &'a A: Add<&'a A, Output = A>, + for<'a> &'a A: Sub { #[inline] fn next_back(&mut self) -> Option { @@ -2697,80 +2646,6 @@ impl Iterator for StepBy> { } } -/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping. -#[derive(Clone)] -#[unstable(feature = "core", - reason = "likely to be replaced by range notation and adapters")] -pub struct RangeStepInclusive { - state: A, - stop: A, - step: A, - rev: bool, - done: bool, -} - -/// Return an iterator over the range [start, stop] by `step`. -/// -/// It handles overflow by stopping. -/// -/// # Examples -/// -/// ``` -/// # #![feature(core)] -/// use std::iter::range_step_inclusive; -/// -/// for i in range_step_inclusive(0, 10, 2) { -/// println!("{}", i); -/// } -/// ``` -/// -/// This prints: -/// -/// ```text -/// 0 -/// 2 -/// 4 -/// 6 -/// 8 -/// 10 -/// ``` -#[inline] -#[unstable(feature = "core", - reason = "likely to be replaced by range notation and adapters")] -#[allow(deprecated)] -pub fn range_step_inclusive(start: A, stop: A, step: A) -> RangeStepInclusive { - let rev = step < Int::zero(); - RangeStepInclusive { - state: start, - stop: stop, - step: step, - rev: rev, - done: false, - } -} - -#[unstable(feature = "core", - reason = "likely to be replaced by range notation and adapters")] -#[allow(deprecated)] -impl Iterator for RangeStepInclusive { - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - if !self.done && ((self.rev && self.state >= self.stop) || - (!self.rev && self.state <= self.stop)) { - let result = self.state; - match self.state.checked_add(self.step) { - Some(x) => self.state = x, - None => self.done = true - } - Some(result) - } else { - None - } - } -} - macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -2780,24 +2655,17 @@ macro_rules! range_exact_iter_impl { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] -impl Iterator for ops::Range { +impl Iterator for ops::Range where + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] fn next(&mut self) -> Option { if self.start < self.end { - match self.start.step(&A::one()) { - Some(mut n) => { - mem::swap(&mut n, &mut self.start); - Some(n) - }, - None => { - let mut n = self.end.clone(); - mem::swap(&mut n, &mut self.start); - Some(n) - - } - } + let mut n = &self.start + &A::one(); + mem::swap(&mut n, &mut self.start); + Some(n) } else { None } @@ -2805,10 +2673,9 @@ impl Iterator for ops::Range { #[inline] fn size_hint(&self) -> (usize, Option) { - if let Some(hint) = Step::steps_between(&self.start, &self.end, &A::one()) { - (hint, Some(hint)) - } else { - (0, None) + match Step::steps_between(&self.start, &self.end, &A::one()) { + Some(hint) => (hint, Some(hint)), + None => (0, None) } } } @@ -2820,6 +2687,7 @@ range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32); #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] impl DoubleEndedIterator for ops::Range where + for<'a> &'a A: Add<&'a A, Output = A>, for<'a> &'a A: Sub<&'a A, Output = A> { #[inline] @@ -2835,15 +2703,16 @@ impl DoubleEndedIterator for ops::Range where #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] -impl Iterator for ops::RangeFrom { +impl Iterator for ops::RangeFrom where + for<'a> &'a A: Add<&'a A, Output = A> +{ type Item = A; #[inline] fn next(&mut self) -> Option { - self.start.step(&A::one()).map(|mut n| { - mem::swap(&mut n, &mut self.start); - n - }) + let mut n = &self.start + &A::one(); + mem::swap(&mut n, &mut self.start); + Some(n) } } @@ -2885,7 +2754,7 @@ type IterateState = (F, Option, bool); #[unstable(feature = "core")] pub type Iterate = Unfold, fn(&mut IterateState) -> Option>; -/// Create a new iterator that produces an infinite sequence of +/// Creates a new iterator that produces an infinite sequence of /// repeated applications of the given function `f`. #[unstable(feature = "core")] pub fn iterate(seed: T, f: F) -> Iterate where @@ -2899,13 +2768,8 @@ pub fn iterate(seed: T, f: F) -> Iterate where let &mut (ref mut f, ref mut val, ref mut first) = st; if *first { *first = false; - } else { - match val.take() { - Some(x) => { - *val = Some((*f)(x)) - } - None => {} - } + } else if let Some(x) = val.take() { + *val = Some((*f)(x)) } val.clone() } @@ -2916,7 +2780,7 @@ pub fn iterate(seed: T, f: F) -> Iterate where Unfold::new((f, Some(seed), true), next) } -/// Create a new iterator that endlessly repeats the element `elt`. +/// Creates a new iterator that endlessly repeats the element `elt`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn repeat(elt: T) -> Repeat { @@ -3003,7 +2867,7 @@ pub mod order { } } - /// Compare `a` and `b` for nonequality (Using partial equality, `PartialEq`) + /// Compares `a` and `b` for nonequality (Using partial equality, `PartialEq`) pub fn ne(mut a: L, mut b: R) -> bool where L::Item: PartialEq, { @@ -3016,7 +2880,7 @@ pub mod order { } } - /// Return `a` < `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` < `b` lexicographically (Using partial order, `PartialOrd`) pub fn lt(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -3030,7 +2894,7 @@ pub mod order { } } - /// Return `a` <= `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` <= `b` lexicographically (Using partial order, `PartialOrd`) pub fn le(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -3044,7 +2908,7 @@ pub mod order { } } - /// Return `a` > `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` > `b` lexicographically (Using partial order, `PartialOrd`) pub fn gt(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { @@ -3058,7 +2922,7 @@ pub mod order { } } - /// Return `a` >= `b` lexicographically (Using partial order, `PartialOrd`) + /// Returns `a` >= `b` lexicographically (Using partial order, `PartialOrd`) pub fn ge(mut a: L, mut b: R) -> bool where L::Item: PartialOrd, { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2189e2c3ad..249f0a0c38 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -38,7 +38,7 @@ //! provided by the [rlibc crate](https://crates.io/crates/rlibc). //! //! * `rust_begin_unwind` - This function takes three arguments, a -//! `fmt::Arguments`, a `&str`, and a `usize`. These three arguments dictate +//! `fmt::Arguments`, a `&str`, and a `u32`. These three arguments dictate //! the panic message, the file at which panic was invoked, and the line. //! It is up to consumers of this core library to define this panic //! function; it is only required to never return. @@ -108,6 +108,7 @@ mod uint_macros; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; +#[macro_use] pub mod num; /* The libcore prelude, not as all-encompassing as the libstd prelude */ @@ -157,6 +158,7 @@ mod tuple; #[doc(hidden)] mod core { + pub use intrinsics; pub use panicking; pub use fmt; pub use clone; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 751bd7353e..ece419af95 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -182,7 +182,7 @@ macro_rules! try { /// ``` #[macro_export] macro_rules! write { - ($dst:expr, $($arg:tt)*) => ((&mut *$dst).write_fmt(format_args!($($arg)*))) + ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } /// Equivalent to the `write!` macro, except that a newline is appended after @@ -229,7 +229,6 @@ macro_rules! writeln { /// Iterators: /// /// ``` -/// # #![feature(core)] /// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3 /// for i in 0.. { /// if 3*i < i { panic!("u32 overflow"); } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 619f983aee..fdabdbc5ed 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -35,6 +35,16 @@ use hash::Hasher; #[stable(feature = "rust1", since = "1.0.0")] #[lang="send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[cfg(not(stage0))] +pub unsafe trait Send { + // empty. +} + +/// Types able to be transferred across thread boundaries. +#[stable(feature = "rust1", since = "1.0.0")] +#[lang="send"] +#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[cfg(stage0)] pub unsafe trait Send : MarkerTrait { // empty. } @@ -50,6 +60,17 @@ impl !Send for Managed { } #[lang="sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable +#[cfg(not(stage0))] +pub trait Sized { + // Empty. +} + +/// Types with a constant size known at compile-time. +#[stable(feature = "rust1", since = "1.0.0")] +#[lang="sized"] +#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable +#[cfg(stage0)] pub trait Sized : MarkerTrait { // Empty. } @@ -197,9 +218,20 @@ pub trait Copy : Clone { /// the `sync` crate do ensure that any mutation cannot cause data /// races. Hence these types are `Sync`. /// -/// 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). +/// 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). +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +#[lang="sync"] +#[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] +pub unsafe trait Sync { + // Empty +} + +/// dox +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] #[lang="sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] @@ -269,95 +301,71 @@ macro_rules! impls{ ) } -/// `MarkerTrait` is intended to be used as the supertrait for traits -/// that don't have any methods but instead serve just to designate -/// categories of types. An example would be the `Send` trait, which -/// indicates types that are sendable: `Send` does not itself offer -/// any methods, but instead is used to gate access to data. -/// -/// FIXME. Better documentation needed here! +/// dox #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(stage0)] pub trait MarkerTrait : PhantomFn { } -// ~~~~~ <-- FIXME(#22806)? -// -// Marker trait has been made invariant so as to avoid inf recursion, -// but we should ideally solve the underlying problem. That's a bit -// complicated. -impl MarkerTrait for T { } +#[cfg(stage0)] +impl MarkerTrait for T {} -/// `PhantomFn` is a marker trait for use with traits that contain -/// type or lifetime parameters that do not appear in any of their -/// methods. In that case, you can either remove those parameters, or -/// add a `PhantomFn` supertrait that reflects the signature of -/// methods that compiler should "pretend" exists. This most commonly -/// occurs for traits with no methods: in that particular case, you -/// can extend `MarkerTrait`, which is equivalent to -/// `PhantomFn`. +/// dox +#[lang="phantom_fn"] +#[cfg(stage0)] +pub trait PhantomFn { +} + +/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, +/// even though it does not. This allows you to inform the compiler about certain safety properties +/// of your code. +/// +/// Though they both have scary names, `PhantomData` and "phantom types" are unrelated. 👻👻👻 /// /// # Examples /// -/// As an example, consider a trait with no methods like `Even`, meant -/// to represent types that are "even": +/// ## Unused lifetime parameter /// -/// ```rust,ignore -/// trait Even { } -/// ``` +/// Perhaps the most common time that `PhantomData` is required is +/// with a struct that has an unused lifetime parameter, typically as +/// part of some unsafe code. For example, here is a struct `Slice` +/// that has two pointers of type `*const T`, presumably pointing into +/// an array somewhere: /// -/// In this case, because the implicit parameter `Self` is unused, the -/// compiler will issue an error. The only purpose of this trait is to -/// categorize types (and hence instances of those types) as "even" or -/// not, so if we *were* going to have a method, it might look like: -/// -/// ```rust,ignore -/// trait Even { -/// fn is_even(self) -> bool { true } +/// ```ignore +/// struct Slice<'a, T> { +/// start: *const T, +/// end: *const T, /// } /// ``` /// -/// Therefore, we can model a method like this as follows: +/// The intention is that the underlying data is only valid for the +/// lifetime `'a`, so `Slice` should not outlive `'a`. However, this +/// intent is not expressed in the code, since there are no uses of +/// the lifetime `'a` and hence it is not clear what data it applies +/// to. We can correct this by telling the compiler to act *as if* the +/// `Slice` struct contained a borrowed reference `&'a T`: /// /// ``` -/// use std::marker::PhantomFn; -/// trait Even : PhantomFn { } -/// ``` -/// -/// Another equivalent, but clearer, option would be to use -/// `MarkerTrait`: +/// use std::marker::PhantomData; /// +/// struct Slice<'a, T:'a> { +/// start: *const T, +/// end: *const T, +/// phantom: PhantomData<&'a T> +/// } /// ``` -/// # #![feature(core)] -/// use std::marker::MarkerTrait; -/// trait Even : MarkerTrait { } -/// ``` -/// -/// # Parameters /// -/// - `A` represents the type of the method's argument. You can use a -/// tuple to represent "multiple" arguments. Any types appearing here -/// will be considered "contravariant". -/// - `R`, if supplied, represents the method's return type. This defaults -/// to `()` as it is rarely needed. +/// This also in turn requires that we annotate `T:'a`, indicating +/// that `T` is a type that can be borrowed for the lifetime `'a`. /// -/// # Additional reading +/// ## Unused type parameters /// -/// More details and background can be found in [RFC 738][738]. -/// -/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md -#[lang="phantom_fn"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait PhantomFn { } - -/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, -/// even though it does not. This allows you to inform the compiler about certain safety properties -/// of your code. -/// -/// Though they both have scary names, `PhantomData` and "phantom types" are unrelated. 👻👻👻 -/// -/// # Examples -/// -/// When handling external resources over a foreign function interface, `PhantomData` can -/// prevent mismatches by enforcing types in the method implementations: +/// It sometimes happens that there are unused type parameters that +/// indicate what type of data a struct is "tied" to, even though that +/// data is not actually found in the struct itself. Here is an +/// example where this arises when handling external resources over a +/// foreign function interface. `PhantomData` can prevent +/// mismatches by enforcing types in the method implementations: /// /// ``` /// # trait ResType { fn foo(&self); }; @@ -391,13 +399,21 @@ pub trait PhantomFn { } /// } /// ``` /// -/// Another example: embedding a `PhantomData` will inform the compiler -/// that one or more instances of the type `T` could be dropped when -/// instances of the type itself is dropped, though that may not be -/// apparent from the other structure of the type itself. This is -/// commonly necessary if the structure is using an unsafe pointer -/// like `*mut T` whose referent may be dropped when the type is -/// dropped, as a `*mut T` is otherwise not treated as owned. +/// ## Indicating ownership +/// +/// Adding a field of type `PhantomData` also indicates that your +/// struct owns data of type `T`. This in turn implies that when your +/// struct is dropped, it may in turn drop one or more instances of +/// the type `T`, though that may not be apparent from the other +/// structure of the type itself. This is commonly necessary if the +/// structure is using an unsafe pointer like `*mut T` whose referent +/// may be dropped when the type is dropped, as a `*mut T` is +/// otherwise not treated as owned. +/// +/// If your struct does not in fact *own* the data of type `T`, it is +/// better to use a reference type, like `PhantomData<&'a T>` +/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so +/// as not to indicate ownership. #[lang="phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; @@ -444,8 +460,15 @@ mod impls { /// [1]: http://en.wikipedia.org/wiki/Parametricity #[rustc_reflect_like] #[unstable(feature = "core", reason = "requires RFC and more experience")] -pub trait Reflect : MarkerTrait { -} +#[allow(deprecated)] +#[cfg(not(stage0))] +pub trait Reflect {} + +/// dox +#[rustc_reflect_like] +#[unstable(feature = "core", reason = "requires RFC and more experience")] +#[cfg(stage0)] +pub trait Reflect: MarkerTrait {} impl Reflect for .. { } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 249beb6295..c4128e7976 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -134,7 +134,7 @@ pub fn align_of_val(_val: &T) -> usize { align_of::() } -/// Create a value initialized to zero. +/// Creates a value initialized to zero. /// /// This function is similar to allocating space for a local variable and zeroing it out (an unsafe /// operation). @@ -158,7 +158,7 @@ pub unsafe fn zeroed() -> T { intrinsics::init() } -/// Create a value initialized to an unspecified series of bytes. +/// Creates a value initialized to an unspecified series of bytes. /// /// The byte sequence usually indicates that the value at the memory /// in question has been dropped. Thus, *if* T carries a drop flag, @@ -179,7 +179,7 @@ pub unsafe fn dropped() -> T { dropped_impl() } -/// Create an uninitialized value. +/// Creates an uninitialized value. /// /// 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 @@ -234,7 +234,7 @@ pub fn swap(x: &mut T, y: &mut T) { } } -/// Replace the value at a mutable location with a new one, returning the old value, without +/// Replaces the value at a mutable location with a new one, returning the old value, without /// deinitialising or copying either one. /// /// This is primarily used for transferring and swapping ownership of a value in a mutable diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 230587b726..9ea44c39fe 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -10,11 +10,17 @@ //! Exposes the NonZero lang item which provides optimization hints. -use marker::{Sized, MarkerTrait}; +use marker::Sized; use ops::Deref; +#[cfg(stage0)] use marker::MarkerTrait; /// Unsafe trait to indicate what types are usable with the NonZero struct -pub unsafe trait Zeroable : MarkerTrait {} +#[cfg(not(stage0))] +pub unsafe trait Zeroable {} + +/// Unsafe trait to indicate what types are usable with the NonZero struct +#[cfg(stage0)] +pub unsafe trait Zeroable: MarkerTrait {} unsafe impl Zeroable for *const T {} unsafe impl Zeroable for *mut T {} @@ -37,7 +43,7 @@ unsafe impl Zeroable for u64 {} pub struct NonZero(T); impl NonZero { - /// Create an instance of NonZero with the provided value. + /// Creates an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline(always)] pub unsafe fn new(inner: T) -> NonZero { diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 12b45a766b..50dd3f1661 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -16,11 +16,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +use prelude::*; + use intrinsics; use mem; -use num::Float; +use num::{Float, ParseFloatError}; use num::FpCategory as Fp; -use option::Option; #[stable(feature = "rust1", since = "1.0.0")] pub const RADIX: u32 = 2; @@ -33,19 +34,6 @@ pub const DIGITS: u32 = 6; #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f32 = 1.19209290e-07_f32; -/// Smallest finite f32 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f32::MIN`")] -pub const MIN_VALUE: f32 = -3.40282347e+38_f32; -/// Smallest positive, normalized f32 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f32::MIN_POSITIVE`")] -pub const MIN_POS_VALUE: f32 = 1.17549435e-38_f32; -/// Largest finite f32 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f32::MAX`")] -pub const MAX_VALUE: f32 = 3.40282347e+38_f32; - /// Smallest finite f32 value #[stable(feature = "rust1", since = "1.0.0")] pub const MIN: f32 = -3.40282347e+38_f32; @@ -118,26 +106,14 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_SQRT_PI: f32 = 1.12837916709551257389615890312154517_f32; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to FRAC_2_SQRT_PI")] - pub const FRAC_2_SQRTPI: f32 = 1.12837916709551257389615890312154517_f32; - /// sqrt(2.0) #[stable(feature = "rust1", since = "1.0.0")] pub const SQRT_2: f32 = 1.41421356237309504880168872420969808_f32; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to SQRT_2")] - pub const SQRT2: f32 = 1.41421356237309504880168872420969808_f32; - /// 1.0/sqrt(2.0) #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to FRAC_1_SQRT_2")] - pub const FRAC_1_SQRT2: f32 = 0.707106781186547524400844362104849039_f32; - /// Euler's number #[stable(feature = "rust1", since = "1.0.0")] pub const E: f32 = 2.71828182845904523536028747135266250_f32; @@ -179,6 +155,8 @@ impl Float for f32 { #[inline] fn one() -> f32 { 1.0 } + from_str_radix_float_impl! { f32 } + /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { self != self } @@ -218,56 +196,6 @@ impl Float for f32 { } } - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn mantissa_digits(_: Option) -> usize { MANTISSA_DIGITS as usize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn digits(_: Option) -> usize { DIGITS as usize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn epsilon() -> f32 { EPSILON } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_exp(_: Option) -> isize { MIN_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_exp(_: Option) -> isize { MAX_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_10_exp(_: Option) -> isize { MIN_10_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_10_exp(_: Option) -> isize { MAX_10_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_value() -> f32 { MIN } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_pos_value(_: Option) -> f32 { MIN_POSITIVE } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_value() -> f32 { MAX } - /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8) { let bits: u32 = unsafe { mem::transmute(self) }; @@ -310,9 +238,6 @@ impl Float for f32 { /// The fractional part of the number, satisfying: /// /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// /// let x = 1.65f32; /// assert!(x == x.trunc() + x.fract()) /// ``` diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 058acedd9c..62b566e7eb 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -16,11 +16,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +use prelude::*; + use intrinsics; use mem; -use num::Float; use num::FpCategory as Fp; -use option::Option; +use num::{Float, ParseFloatError}; #[stable(feature = "rust1", since = "1.0.0")] pub const RADIX: u32 = 2; @@ -33,19 +34,6 @@ pub const DIGITS: u32 = 15; #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; -/// Smallest finite f64 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f64::MIN`")] -pub const MIN_VALUE: f64 = -1.7976931348623157e+308_f64; -/// Smallest positive, normalized f64 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f64::MIN_POSITIVE`")] -pub const MIN_POS_VALUE: f64 = 2.2250738585072014e-308_f64; -/// Largest finite f64 value -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "use `std::f64::MAX`")] -pub const MAX_VALUE: f64 = 1.7976931348623157e+308_f64; - /// Smallest finite f64 value #[stable(feature = "rust1", since = "1.0.0")] pub const MIN: f64 = -1.7976931348623157e+308_f64; @@ -118,26 +106,14 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_SQRT_PI: f64 = 1.12837916709551257389615890312154517_f64; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to FRAC_2_SQRT_PI")] - pub const FRAC_2_SQRTPI: f64 = 1.12837916709551257389615890312154517_f64; - /// sqrt(2.0) #[stable(feature = "rust1", since = "1.0.0")] pub const SQRT_2: f64 = 1.41421356237309504880168872420969808_f64; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to SQRT_2")] - pub const SQRT2: f64 = 1.41421356237309504880168872420969808_f64; - /// 1.0/sqrt(2.0) #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to FRAC_1_SQRT_2")] - pub const FRAC_1_SQRT2: f64 = 0.707106781186547524400844362104849039_f64; - /// Euler's number #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; @@ -179,6 +155,8 @@ impl Float for f64 { #[inline] fn one() -> f64 { 1.0 } + from_str_radix_float_impl! { f64 } + /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { self != self } @@ -218,56 +196,6 @@ impl Float for f64 { } } - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn mantissa_digits(_: Option) -> usize { MANTISSA_DIGITS as usize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn digits(_: Option) -> usize { DIGITS as usize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn epsilon() -> f64 { EPSILON } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_exp(_: Option) -> isize { MIN_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_exp(_: Option) -> isize { MAX_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_10_exp(_: Option) -> isize { MIN_10_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_10_exp(_: Option) -> isize { MAX_10_EXP as isize } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_value() -> f64 { MIN } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn min_pos_value(_: Option) -> f64 { MIN_POSITIVE } - - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0")] - fn max_value() -> f64 { MAX } - /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8) { let bits: u64 = unsafe { mem::transmute(self) }; @@ -310,9 +238,6 @@ impl Float for f64 { /// The fractional part of the number, satisfying: /// /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// /// let x = 1.65f64; /// assert!(x == x.trunc() + x.fract()) /// ``` diff --git a/src/libcore/num/float_macros.rs b/src/libcore/num/float_macros.rs index b3adef53da..5ee0dc19f9 100644 --- a/src/libcore/num/float_macros.rs +++ b/src/libcore/num/float_macros.rs @@ -18,3 +18,145 @@ macro_rules! assert_approx_eq { "{} is not approximately equal to {}", *a, *b); }) } + +macro_rules! from_str_radix_float_impl { + ($T:ty) => { + fn from_str_radix(src: &str, radix: u32) + -> Result<$T, ParseFloatError> { + use num::FloatErrorKind::*; + use num::ParseFloatError as PFE; + + // Special values + match src { + "inf" => return Ok(Float::infinity()), + "-inf" => return Ok(Float::neg_infinity()), + "NaN" => return Ok(Float::nan()), + _ => {}, + } + + let (is_positive, src) = match src.slice_shift_char() { + None => return Err(PFE { kind: Empty }), + Some(('-', "")) => return Err(PFE { kind: Empty }), + Some(('-', src)) => (false, src), + Some((_, _)) => (true, src), + }; + + // The significand to accumulate + let mut sig = if is_positive { 0.0 } else { -0.0 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, usize)>; + + // Parse the integer part of the significand + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // shift significand one digit left + sig = sig * (radix as $T); + + // add/subtract current digit depending on sign + if is_positive { + sig = sig + ((digit as isize) as $T); + } else { + sig = sig - ((digit as isize) as $T); + } + + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if prev_sig != 0.0 { + if is_positive && sig <= prev_sig + { return Ok(Float::infinity()); } + if !is_positive && sig >= prev_sig + { return Ok(Float::neg_infinity()); } + + // Detect overflow by reversing the shift-and-add process + if is_positive && (prev_sig != (sig - digit as $T) / radix as $T) + { return Ok(Float::infinity()); } + if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T) + { return Ok(Float::neg_infinity()); } + } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = 1.0; + for (i, c) in cs.by_ref() { + match c.to_digit(radix) { + Some(digit) => { + // Decrease power one order of magnitude + power = power / (radix as $T); + // add/subtract current digit depending on sign + sig = if is_positive { + sig + (digit as $T) * power + } else { + sig - (digit as $T) * power + }; + // Detect overflow by comparing to last value + if is_positive && sig < prev_sig + { return Ok(Float::infinity()); } + if !is_positive && sig > prev_sig + { return Ok(Float::neg_infinity()); } + prev_sig = sig; + }, + None => match c { + 'e' | 'E' | 'p' | 'P' => { + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return Err(PFE { kind: Invalid }); + }, + }, + } + } + } + + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base = match c { + 'E' | 'e' if radix == 10 => 10.0, + 'P' | 'p' if radix == 16 => 2.0, + _ => return Err(PFE { kind: Invalid }), + }; + + // Parse the exponent as decimal integer + let src = &src[offset..]; + let (is_positive, exp) = match src.slice_shift_char() { + Some(('-', src)) => (false, src.parse::()), + Some(('+', src)) => (true, src.parse::()), + Some((_, _)) => (true, src.parse::()), + None => return Err(PFE { kind: Invalid }), + }; + + match (is_positive, exp) { + (true, Ok(exp)) => base.powi(exp as i32), + (false, Ok(exp)) => 1.0 / base.powi(exp as i32), + (_, Err(_)) => return Err(PFE { kind: Invalid }), + } + }, + None => 1.0, // no exponent + }; + + Ok(sig * exp) + } + } +} diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index fe0d6d13c4..3113521e0a 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -15,11 +15,11 @@ macro_rules! int_module { ($T:ty, $bits:expr) => ( // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of // calling the `mem::size_of` function. #[unstable(feature = "core")] -pub const BITS : u32 = $bits; +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 = "core")] -pub const BYTES : u32 = ($bits / 8); +pub const BYTES : usize = ($bits / 8); // FIXME(#11621): Should be deprecated once CTFE is implemented in favour of // calling the `Bounded::min_value` function. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 28e0bcf13d..1b0dd73d10 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,18 +15,14 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -use self::wrapping::{OverflowingOps, WrappingOps}; +use self::wrapping::OverflowingOps; use char::CharExt; -use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord}; +use cmp::{Eq, PartialOrd}; use fmt; use intrinsics; -use iter::Iterator; use marker::Copy; use mem::size_of; -use ops::{Add, Sub, Mul, Div, Rem, Neg}; -use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; use str::{FromStr, StrExt}; @@ -86,406 +82,19 @@ macro_rules! zero_one_impl { } zero_one_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } -/// A built-in signed or unsigned integer. -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", - reason = "replaced by inherent methods; for generics, use rust-lang/num")] -#[allow(deprecated)] -pub trait Int - : Copy + Clone - + NumCast - + PartialOrd + Ord - + PartialEq + Eq - + Add - + Sub - + Mul - + Div - + Rem - + Not - + BitAnd - + BitOr - + BitXor - + Shl - + Shr - + WrappingOps - + OverflowingOps -{ - /// Returns the `0` value of this integer type. - // FIXME (#5527): Should be an associated constant - #[unstable(feature = "core", - reason = "unsure about its place in the world")] - fn zero() -> Self; - - /// Returns the `1` value of this integer type. - // FIXME (#5527): Should be an associated constant - #[unstable(feature = "core", - reason = "unsure about its place in the world")] - fn one() -> Self; - - /// Returns the smallest value that can be represented by this integer type. - // FIXME (#5527): Should be and associated constant - #[unstable(feature = "core", - reason = "unsure about its place in the world")] - fn min_value() -> Self; - - /// Returns the largest value that can be represented by this integer type. - // FIXME (#5527): Should be and associated constant - #[unstable(feature = "core", - reason = "unsure about its place in the world")] - fn max_value() -> Self; - - /// Returns the number of ones in the binary representation of `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0b01001100u8; - /// - /// assert_eq!(n.count_ones(), 3); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - fn count_ones(self) -> u32; - - /// Returns the number of zeros in the binary representation of `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0b01001100u8; - /// - /// assert_eq!(n.count_zeros(), 5); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - #[inline] - fn count_zeros(self) -> u32 { - (!self).count_ones() - } - - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0b0101000u16; - /// - /// assert_eq!(n.leading_zeros(), 10); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - fn leading_zeros(self) -> u32; - - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0b0101000u16; - /// - /// assert_eq!(n.trailing_zeros(), 3); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - fn trailing_zeros(self) -> u32; - - /// Shifts the bits to the left by a specified amount amount, `n`, wrapping - /// the truncated bits to the end of the resulting integer. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// let m = 0x3456789ABCDEF012u64; - /// - /// assert_eq!(n.rotate_left(12), m); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - fn rotate_left(self, n: u32) -> Self; - - /// Shifts the bits to the right by a specified amount amount, `n`, wrapping - /// the truncated bits to the beginning of the resulting integer. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// let m = 0xDEF0123456789ABCu64; - /// - /// assert_eq!(n.rotate_right(12), m); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - fn rotate_right(self, n: u32) -> Self; - - /// Reverses the byte order of the integer. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// let m = 0xEFCDAB8967452301u64; - /// - /// assert_eq!(n.swap_bytes(), m); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn swap_bytes(self) -> Self; - - /// Convert an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are swapped. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(Int::from_be(n), n) - /// } else { - /// assert_eq!(Int::from_be(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } - } - - /// Convert an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are swapped. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(Int::from_le(n), n) - /// } else { - /// assert_eq!(Int::from_le(n), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } - } - - /// Convert `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are swapped. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n) - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } - } - - /// Convert `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are swapped. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// let n = 0x0123456789ABCDEFu64; - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n) - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } - } - - /// Checked integer addition. Computes `self + other`, returning `None` if - /// overflow occurred. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!(5u16.checked_add(65530), Some(65535)); - /// assert_eq!(6u16.checked_add(65530), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn checked_add(self, other: Self) -> Option; - - /// Checked integer subtraction. Computes `self - other`, returning `None` - /// if underflow occurred. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!((-127i8).checked_sub(1), Some(-128)); - /// assert_eq!((-128i8).checked_sub(1), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn checked_sub(self, other: Self) -> Option; - - /// Checked integer multiplication. Computes `self * other`, returning - /// `None` if underflow or overflow occurred. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!(5u8.checked_mul(51), Some(255)); - /// assert_eq!(5u8.checked_mul(52), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn checked_mul(self, other: Self) -> Option; - - /// Checked integer division. Computes `self / other`, returning `None` if - /// `other == 0` or the operation results in underflow or overflow. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!((-127i8).checked_div(-1), Some(127)); - /// assert_eq!((-128i8).checked_div(-1), None); - /// assert_eq!((1i8).checked_div(0), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn checked_div(self, other: Self) -> Option; - - /// Saturating integer addition. Computes `self + other`, saturating at - /// the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!(5u16.saturating_add(65534), 65535); - /// assert_eq!((-5i16).saturating_add(-32767), -32768); - /// assert_eq!(100u32.saturating_add(4294967294), 4294967295); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn saturating_add(self, other: Self) -> Self { - match self.checked_add(other) { - Some(x) => x, - None if other >= Int::zero() => Int::max_value(), - None => Int::min_value(), - } - } - - /// Saturating integer subtraction. Computes `self - other`, saturating at - /// the numeric bounds instead of overflowing. - /// - /// # Examples - /// - /// ``` - /// use std::num::Int; - /// - /// assert_eq!(5u16.saturating_sub(65534), 0); - /// assert_eq!(5i16.saturating_sub(-32767), 32767); - /// assert_eq!(100u32.saturating_sub(4294967294), 0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn saturating_sub(self, other: Self) -> Self { - match self.checked_sub(other) { - Some(x) => x, - None if other >= Int::zero() => Int::min_value(), - None => Int::max_value(), +macro_rules! zero_one_impl_float { + ($($t:ty)*) => ($( + impl Zero for $t { + #[inline] + fn zero() -> $t { 0.0 } } - } - - /// Raises self to the power of `exp`, using exponentiation by squaring. - /// - /// # Examples - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Int; - /// - /// assert_eq!(2.pow(4), 16); - /// ``` - #[unstable(feature = "core", - reason = "pending integer conventions")] - #[inline] - fn pow(self, mut exp: u32) -> Self { - let mut base = self; - let mut acc: Self = Int::one(); - - let mut prev_base = self; - let mut base_oflo = false; - while exp > 0 { - if (exp & 1) == 1 { - if base_oflo { - // ensure overflow occurs in the same manner it - // would have otherwise (i.e. signal any exception - // it would have otherwise). - acc = acc * (prev_base * prev_base); - } else { - acc = acc * base; - } - } - prev_base = base; - let (new_base, new_base_oflo) = base.overflowing_mul(base); - base = new_base; - base_oflo = new_base_oflo; - exp /= 2; + impl One for $t { + #[inline] + fn one() -> $t { 1.0 } } - acc - } + )*) } +zero_one_impl_float! { f32 f64 } macro_rules! checked_op { ($T:ty, $U:ty, $op:path, $x:expr, $y:expr) => {{ @@ -494,328 +103,13 @@ macro_rules! checked_op { }} } -macro_rules! uint_impl { - ($T:ty = $ActualT:ty, $BITS:expr, - $ctpop:path, - $ctlz:path, - $cttz:path, - $bswap:path, - $add_with_overflow:path, - $sub_with_overflow:path, - $mul_with_overflow:path) => { - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl Int for $T { - #[inline] - fn zero() -> $T { 0 } - - #[inline] - fn one() -> $T { 1 } - - #[inline] - fn min_value() -> $T { 0 } - - #[inline] - fn max_value() -> $T { !0 } - - #[inline] - fn count_ones(self) -> u32 { - unsafe { $ctpop(self as $ActualT) as u32 } - } - - #[inline] - fn leading_zeros(self) -> u32 { - unsafe { $ctlz(self as $ActualT) as u32 } - } - - #[inline] - fn trailing_zeros(self) -> u32 { - unsafe { $cttz(self as $ActualT) as u32 } - } - - #[inline] - fn rotate_left(self, n: u32) -> $T { - // Protect against undefined behaviour for over-long bit shifts - let n = n % $BITS; - (self << n) | (self >> (($BITS - n) % $BITS)) - } - - #[inline] - fn rotate_right(self, n: u32) -> $T { - // Protect against undefined behaviour for over-long bit shifts - let n = n % $BITS; - (self >> n) | (self << (($BITS - n) % $BITS)) - } - - #[inline] - fn swap_bytes(self) -> $T { - unsafe { $bswap(self as $ActualT) as $T } - } - - #[inline] - fn checked_add(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $add_with_overflow, self, other) - } - - #[inline] - fn checked_sub(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $sub_with_overflow, self, other) - } - - #[inline] - fn checked_mul(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $mul_with_overflow, self, other) - } - - #[inline] - fn checked_div(self, v: $T) -> Option<$T> { - match v { - 0 => None, - v => Some(self / v), - } - } - } - } -} - /// Swapping a single byte is a no-op. This is marked as `unsafe` for /// consistency with the other `bswap` intrinsics. unsafe fn bswap8(x: u8) -> u8 { x } -uint_impl! { u8 = u8, 8, - intrinsics::ctpop8, - intrinsics::ctlz8, - intrinsics::cttz8, - bswap8, - intrinsics::u8_add_with_overflow, - intrinsics::u8_sub_with_overflow, - intrinsics::u8_mul_with_overflow } - -uint_impl! { u16 = u16, 16, - intrinsics::ctpop16, - intrinsics::ctlz16, - intrinsics::cttz16, - intrinsics::bswap16, - intrinsics::u16_add_with_overflow, - intrinsics::u16_sub_with_overflow, - intrinsics::u16_mul_with_overflow } - -uint_impl! { u32 = u32, 32, - intrinsics::ctpop32, - intrinsics::ctlz32, - intrinsics::cttz32, - intrinsics::bswap32, - intrinsics::u32_add_with_overflow, - intrinsics::u32_sub_with_overflow, - intrinsics::u32_mul_with_overflow } - -uint_impl! { u64 = u64, 64, - intrinsics::ctpop64, - intrinsics::ctlz64, - intrinsics::cttz64, - intrinsics::bswap64, - intrinsics::u64_add_with_overflow, - intrinsics::u64_sub_with_overflow, - intrinsics::u64_mul_with_overflow } - -#[cfg(target_pointer_width = "32")] -uint_impl! { usize = u32, 32, - intrinsics::ctpop32, - intrinsics::ctlz32, - intrinsics::cttz32, - intrinsics::bswap32, - intrinsics::u32_add_with_overflow, - intrinsics::u32_sub_with_overflow, - intrinsics::u32_mul_with_overflow } - -#[cfg(target_pointer_width = "64")] -uint_impl! { usize = u64, 64, - intrinsics::ctpop64, - intrinsics::ctlz64, - intrinsics::cttz64, - intrinsics::bswap64, - intrinsics::u64_add_with_overflow, - intrinsics::u64_sub_with_overflow, - intrinsics::u64_mul_with_overflow } - -macro_rules! int_impl { - ($T:ty = $ActualT:ty, $UnsignedT:ty, $BITS:expr, - $add_with_overflow:path, - $sub_with_overflow:path, - $mul_with_overflow:path) => { - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl Int for $T { - #[inline] - fn zero() -> $T { 0 } - - #[inline] - fn one() -> $T { 1 } - - #[inline] - fn min_value() -> $T { (-1 as $T) << ($BITS - 1) } - - #[inline] - fn max_value() -> $T { let min: $T = Int::min_value(); !min } - - #[inline] - fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - - #[inline] - fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - - #[inline] - fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - - #[inline] - fn rotate_left(self, n: u32) -> $T { - (self as $UnsignedT).rotate_left(n) as $T - } - - #[inline] - fn rotate_right(self, n: u32) -> $T { - (self as $UnsignedT).rotate_right(n) as $T - } - - #[inline] - fn swap_bytes(self) -> $T { - (self as $UnsignedT).swap_bytes() as $T - } - - #[inline] - fn checked_add(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $add_with_overflow, self, other) - } - - #[inline] - fn checked_sub(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $sub_with_overflow, self, other) - } - - #[inline] - fn checked_mul(self, other: $T) -> Option<$T> { - checked_op!($T, $ActualT, $mul_with_overflow, self, other) - } - - #[inline] - fn checked_div(self, v: $T) -> Option<$T> { - match v { - 0 => None, - -1 if self == Int::min_value() - => None, - v => Some(self / v), - } - } - } - } -} - -int_impl! { i8 = i8, u8, 8, - intrinsics::i8_add_with_overflow, - intrinsics::i8_sub_with_overflow, - intrinsics::i8_mul_with_overflow } - -int_impl! { i16 = i16, u16, 16, - intrinsics::i16_add_with_overflow, - intrinsics::i16_sub_with_overflow, - intrinsics::i16_mul_with_overflow } - -int_impl! { i32 = i32, u32, 32, - intrinsics::i32_add_with_overflow, - intrinsics::i32_sub_with_overflow, - intrinsics::i32_mul_with_overflow } - -int_impl! { i64 = i64, u64, 64, - intrinsics::i64_add_with_overflow, - intrinsics::i64_sub_with_overflow, - intrinsics::i64_mul_with_overflow } - -#[cfg(target_pointer_width = "32")] -int_impl! { isize = i32, u32, 32, - intrinsics::i32_add_with_overflow, - intrinsics::i32_sub_with_overflow, - intrinsics::i32_mul_with_overflow } - -#[cfg(target_pointer_width = "64")] -int_impl! { isize = i64, u64, 64, - intrinsics::i64_add_with_overflow, - intrinsics::i64_sub_with_overflow, - intrinsics::i64_mul_with_overflow } - -/// A built-in two's complement integer. -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", - reason = "replaced by inherent methods; for generics, use rust-lang/num")] -#[allow(deprecated)] -pub trait SignedInt - : Int - + Neg -{ - /// Computes the absolute value of `self`. `Int::min_value()` will be - /// returned if the number is `Int::min_value()`. - #[unstable(feature = "core", reason = "overflow in debug builds?")] - fn abs(self) -> Self; - - /// Returns a number representing sign of `self`. - /// - /// - `0` if the number is zero - /// - `1` if the number is positive - /// - `-1` if the number is negative - #[stable(feature = "rust1", since = "1.0.0")] - fn signum(self) -> Self; - - /// Returns `true` if `self` is positive and `false` if the number - /// is zero or negative. - #[stable(feature = "rust1", since = "1.0.0")] - fn is_positive(self) -> bool; - - /// Returns `true` if `self` is negative and `false` if the number - /// is zero or positive. - #[stable(feature = "rust1", since = "1.0.0")] - fn is_negative(self) -> bool; -} - -macro_rules! signed_int_impl { - ($T:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl SignedInt for $T { - #[inline] - fn abs(self) -> $T { - if self.is_negative() { -self } else { self } - } - - #[inline] - fn signum(self) -> $T { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } - } - - #[inline] - fn is_positive(self) -> bool { self > 0 } - - #[inline] - fn is_negative(self) -> bool { self < 0 } - } - } -} - -signed_int_impl! { i8 } -signed_int_impl! { i16 } -signed_int_impl! { i32 } -signed_int_impl! { i64 } -signed_int_impl! { isize } - // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { - ($T:ty = $ActualT:ty, $UnsignedT:ty, $BITS:expr, + ($T:ident = $ActualT:ty, $UnsignedT:ty, $BITS:expr, $add_with_overflow:path, $sub_with_overflow:path, $mul_with_overflow:path) => { @@ -828,10 +122,10 @@ macro_rules! int_impl { /// Returns the largest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] pub fn max_value() -> $T { - let min: $T = Int::min_value(); !min + let min = $T::min_value(); !min } - /// Convert a string slice in a given base to an integer. + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. /// @@ -842,13 +136,12 @@ macro_rules! int_impl { /// /// # Return value /// - /// `None` if the string did not represent a valid number. - /// Otherwise, `Some(n)` where `n` is the integer represented - /// by `src`. + /// `Err(ParseIntError)` if the string did not represent a valid number. + /// Otherwise, `Ok(n)` where `n` is the integer represented by `src`. #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> { - ::from_str_radix(src, radix) + from_str_radix(src, radix) } /// Returns the number of ones in the binary representation of `self`. @@ -856,9 +149,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b01001100u8; /// /// assert_eq!(n.count_ones(), 3); @@ -872,9 +162,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b01001100u8; /// /// assert_eq!(n.count_zeros(), 5); @@ -891,9 +178,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b0101000u16; /// /// assert_eq!(n.leading_zeros(), 10); @@ -910,9 +194,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b0101000u16; /// /// assert_eq!(n.trailing_zeros(), 3); @@ -923,15 +204,12 @@ macro_rules! int_impl { (self as $UnsignedT).trailing_zeros() } - /// Shifts the bits to the left by a specified amount amount, `n`, + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF012u64; /// @@ -943,16 +221,13 @@ macro_rules! int_impl { (self as $UnsignedT).rotate_left(n) as $T } - /// Shifts the bits to the right by a specified amount amount, `n`, + /// Shifts the bits to the right by a specified amount, `n`, /// wrapping the truncated bits to the beginning of the resulting /// integer. /// /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xDEF0123456789ABCu64; /// @@ -969,8 +244,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xEFCDAB8967452301u64; /// @@ -982,7 +255,7 @@ macro_rules! int_impl { (self as $UnsignedT).swap_bytes() as $T } - /// Convert an integer from big endian to the target's endianness. + /// Converts an integer from big endian to the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -990,14 +263,12 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { - /// assert_eq!(Int::from_be(n), n) + /// assert_eq!(u64::from_be(n), n) /// } else { - /// assert_eq!(Int::from_be(n), n.swap_bytes()) + /// assert_eq!(u64::from_be(n), n.swap_bytes()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1006,7 +277,7 @@ macro_rules! int_impl { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } - /// Convert an integer from little endian to the target's endianness. + /// Converts an integer from little endian to the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1014,14 +285,12 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { - /// assert_eq!(Int::from_le(n), n) + /// assert_eq!(u64::from_le(n), n) /// } else { - /// assert_eq!(Int::from_le(n), n.swap_bytes()) + /// assert_eq!(u64::from_le(n), n.swap_bytes()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1030,7 +299,7 @@ macro_rules! int_impl { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } - /// Convert `self` to big endian from the target's endianness. + /// Converts `self` to big endian from the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1038,8 +307,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { @@ -1054,7 +321,7 @@ macro_rules! int_impl { if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } - /// Convert `self` to little endian from the target's endianness. + /// Converts `self` to little endian from the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1062,8 +329,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { @@ -1084,8 +349,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!(5u16.checked_add(65530), Some(65535)); /// assert_eq!(6u16.checked_add(65530), None); /// ``` @@ -1101,8 +364,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!((-127i8).checked_sub(1), Some(-128)); /// assert_eq!((-128i8).checked_sub(1), None); /// ``` @@ -1118,8 +379,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!(5u8.checked_mul(51), Some(255)); /// assert_eq!(5u8.checked_mul(52), None); /// ``` @@ -1135,8 +394,6 @@ macro_rules! int_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!((-127i8).checked_div(-1), Some(127)); /// assert_eq!((-128i8).checked_div(-1), None); /// assert_eq!((1i8).checked_div(0), None); @@ -1210,11 +467,10 @@ macro_rules! int_impl { /// /// # Examples /// - /// ```rust - /// # #![feature(core)] - /// use std::num::Int; + /// ``` + /// let x: i32 = 2; // or any other integer type /// - /// assert_eq!(2.pow(4), 16); + /// assert_eq!(x.pow(4), 16); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1249,7 +505,11 @@ macro_rules! int_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn abs(self) -> $T { - if self.is_negative() { -self } else { self } + if self.is_negative() { + !self + 1 // wrapping_neg + } else { + self + } } /// Returns a number representing sign of `self`. @@ -1349,7 +609,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] pub fn max_value() -> $T { !0 } - /// Convert a string slice in a given base to an integer. + /// Converts a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. /// @@ -1360,13 +620,12 @@ macro_rules! uint_impl { /// /// # Return value /// - /// `None` if the string did not represent a valid number. - /// Otherwise, `Some(n)` where `n` is the integer represented - /// by `src`. + /// `Err(ParseIntError)` if the string did not represent a valid number. + /// Otherwise, `Ok(n)` where `n` is the integer represented by `src`. #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> { - ::from_str_radix(src, radix) + from_str_radix(src, radix) } /// Returns the number of ones in the binary representation of `self`. @@ -1374,9 +633,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b01001100u8; /// /// assert_eq!(n.count_ones(), 3); @@ -1392,9 +648,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b01001100u8; /// /// assert_eq!(n.count_zeros(), 5); @@ -1411,9 +664,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b0101000u16; /// /// assert_eq!(n.leading_zeros(), 10); @@ -1430,9 +680,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0b0101000u16; /// /// assert_eq!(n.trailing_zeros(), 3); @@ -1443,15 +690,12 @@ macro_rules! uint_impl { unsafe { $cttz(self as $ActualT) as u32 } } - /// Shifts the bits to the left by a specified amount amount, `n`, + /// Shifts the bits to the left by a specified amount, `n`, /// wrapping the truncated bits to the end of the resulting integer. /// /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0x3456789ABCDEF012u64; /// @@ -1465,16 +709,13 @@ macro_rules! uint_impl { (self << n) | (self >> (($BITS - n) % $BITS)) } - /// Shifts the bits to the right by a specified amount amount, `n`, + /// Shifts the bits to the right by a specified amount, `n`, /// wrapping the truncated bits to the beginning of the resulting /// integer. /// /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xDEF0123456789ABCu64; /// @@ -1493,8 +734,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// let m = 0xEFCDAB8967452301u64; /// @@ -1506,7 +745,7 @@ macro_rules! uint_impl { unsafe { $bswap(self as $ActualT) as $T } } - /// Convert an integer from big endian to the target's endianness. + /// Converts an integer from big endian to the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1514,14 +753,12 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { - /// assert_eq!(Int::from_be(n), n) + /// assert_eq!(u64::from_be(n), n) /// } else { - /// assert_eq!(Int::from_be(n), n.swap_bytes()) + /// assert_eq!(u64::from_be(n), n.swap_bytes()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1530,7 +767,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "big") { x } else { x.swap_bytes() } } - /// Convert an integer from little endian to the target's endianness. + /// Converts an integer from little endian to the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1538,14 +775,12 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { - /// assert_eq!(Int::from_le(n), n) + /// assert_eq!(u64::from_le(n), n) /// } else { - /// assert_eq!(Int::from_le(n), n.swap_bytes()) + /// assert_eq!(u64::from_le(n), n.swap_bytes()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1554,7 +789,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "little") { x } else { x.swap_bytes() } } - /// Convert `self` to big endian from the target's endianness. + /// Converts `self` to big endian from the target's endianness. /// /// On big endian this is a no-op. On little endian the bytes are /// swapped. @@ -1562,8 +797,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "big") { @@ -1578,7 +811,7 @@ macro_rules! uint_impl { if cfg!(target_endian = "big") { self } else { self.swap_bytes() } } - /// Convert `self` to little endian from the target's endianness. + /// Converts `self` to little endian from the target's endianness. /// /// On little endian this is a no-op. On big endian the bytes are /// swapped. @@ -1586,8 +819,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// let n = 0x0123456789ABCDEFu64; /// /// if cfg!(target_endian = "little") { @@ -1608,8 +839,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!(5u16.checked_add(65530), Some(65535)); /// assert_eq!(6u16.checked_add(65530), None); /// ``` @@ -1625,8 +854,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!((-127i8).checked_sub(1), Some(-128)); /// assert_eq!((-128i8).checked_sub(1), None); /// ``` @@ -1642,8 +869,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!(5u8.checked_mul(51), Some(255)); /// assert_eq!(5u8.checked_mul(52), None); /// ``` @@ -1659,8 +884,6 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// use std::num::Int; - /// /// assert_eq!((-127i8).checked_div(-1), Some(127)); /// assert_eq!((-128i8).checked_div(-1), None); /// assert_eq!((1i8).checked_div(0), None); @@ -1733,10 +956,7 @@ macro_rules! uint_impl { /// # Examples /// /// ```rust - /// # #![feature(core)] - /// use std::num::Int; - /// - /// assert_eq!(2.pow(4), 16); + /// assert_eq!(2i32.pow(4), 16); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -1874,575 +1094,6 @@ impl usize { intrinsics::u64_mul_with_overflow } } -/// A generic trait for converting a value to a number. -#[unstable(feature = "core", reason = "trait is likely to be removed")] -pub trait ToPrimitive { - /// Converts the value of `self` to an `isize`. - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", reason = "use to_isize")] - fn to_int(&self) -> Option { - self.to_i64().and_then(|x| x.to_isize()) - } - - /// Converts the value of `self` to an `isize`. - #[inline] - fn to_isize(&self) -> Option { - self.to_i64().and_then(|x| x.to_isize()) - } - - /// Converts the value of `self` to an `i8`. - #[inline] - fn to_i8(&self) -> Option { - self.to_i64().and_then(|x| x.to_i8()) - } - - /// Converts the value of `self` to an `i16`. - #[inline] - fn to_i16(&self) -> Option { - self.to_i64().and_then(|x| x.to_i16()) - } - - /// Converts the value of `self` to an `i32`. - #[inline] - fn to_i32(&self) -> Option { - self.to_i64().and_then(|x| x.to_i32()) - } - - /// Converts the value of `self` to an `i64`. - fn to_i64(&self) -> Option; - - /// Converts the value of `self` to an `usize`. - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", reason = "use to_usize")] - fn to_uint(&self) -> Option { - self.to_u64().and_then(|x| x.to_usize()) - } - - /// Converts the value of `self` to a `usize`. - #[inline] - fn to_usize(&self) -> Option { - self.to_u64().and_then(|x| x.to_usize()) - } - - /// Converts the value of `self` to an `u8`. - #[inline] - fn to_u8(&self) -> Option { - self.to_u64().and_then(|x| x.to_u8()) - } - - /// Converts the value of `self` to an `u16`. - #[inline] - fn to_u16(&self) -> Option { - self.to_u64().and_then(|x| x.to_u16()) - } - - /// Converts the value of `self` to an `u32`. - #[inline] - fn to_u32(&self) -> Option { - self.to_u64().and_then(|x| x.to_u32()) - } - - /// Converts the value of `self` to an `u64`. - #[inline] - fn to_u64(&self) -> Option; - - /// Converts the value of `self` to an `f32`. - #[inline] - fn to_f32(&self) -> Option { - self.to_f64().and_then(|x| x.to_f32()) - } - - /// Converts the value of `self` to an `f64`. - #[inline] - fn to_f64(&self) -> Option { - self.to_i64().and_then(|x| x.to_f64()) - } -} - -macro_rules! impl_to_primitive_int_to_int { - ($SrcT:ty, $DstT:ty, $slf:expr) => ( - { - if size_of::<$SrcT>() <= size_of::<$DstT>() { - Some($slf as $DstT) - } else { - let n = $slf as i64; - let min_value: $DstT = Int::min_value(); - let max_value: $DstT = Int::max_value(); - if min_value as i64 <= n && n <= max_value as i64 { - Some($slf as $DstT) - } else { - None - } - } - } - ) -} - -macro_rules! impl_to_primitive_int_to_uint { - ($SrcT:ty, $DstT:ty, $slf:expr) => ( - { - let zero: $SrcT = Int::zero(); - let max_value: $DstT = Int::max_value(); - if zero <= $slf && $slf as u64 <= max_value as u64 { - Some($slf as $DstT) - } else { - None - } - } - ) -} - -macro_rules! impl_to_primitive_int { - ($T:ty) => ( - impl ToPrimitive for $T { - #[inline] - fn to_int(&self) -> Option { impl_to_primitive_int_to_int!($T, isize, *self) } - #[inline] - fn to_isize(&self) -> Option { impl_to_primitive_int_to_int!($T, isize, *self) } - #[inline] - fn to_i8(&self) -> Option { impl_to_primitive_int_to_int!($T, i8, *self) } - #[inline] - fn to_i16(&self) -> Option { impl_to_primitive_int_to_int!($T, i16, *self) } - #[inline] - fn to_i32(&self) -> Option { impl_to_primitive_int_to_int!($T, i32, *self) } - #[inline] - fn to_i64(&self) -> Option { impl_to_primitive_int_to_int!($T, i64, *self) } - - #[inline] - fn to_uint(&self) -> Option { impl_to_primitive_int_to_uint!($T, usize, *self) } - #[inline] - fn to_usize(&self) -> Option { impl_to_primitive_int_to_uint!($T, usize, *self) } - #[inline] - fn to_u8(&self) -> Option { impl_to_primitive_int_to_uint!($T, u8, *self) } - #[inline] - fn to_u16(&self) -> Option { impl_to_primitive_int_to_uint!($T, u16, *self) } - #[inline] - fn to_u32(&self) -> Option { impl_to_primitive_int_to_uint!($T, u32, *self) } - #[inline] - fn to_u64(&self) -> Option { impl_to_primitive_int_to_uint!($T, u64, *self) } - - #[inline] - fn to_f32(&self) -> Option { Some(*self as f32) } - #[inline] - fn to_f64(&self) -> Option { Some(*self as f64) } - } - ) -} - -impl_to_primitive_int! { isize } -impl_to_primitive_int! { i8 } -impl_to_primitive_int! { i16 } -impl_to_primitive_int! { i32 } -impl_to_primitive_int! { i64 } - -macro_rules! impl_to_primitive_uint_to_int { - ($DstT:ty, $slf:expr) => ( - { - let max_value: $DstT = Int::max_value(); - if $slf as u64 <= max_value as u64 { - Some($slf as $DstT) - } else { - None - } - } - ) -} - -macro_rules! impl_to_primitive_uint_to_uint { - ($SrcT:ty, $DstT:ty, $slf:expr) => ( - { - if size_of::<$SrcT>() <= size_of::<$DstT>() { - Some($slf as $DstT) - } else { - let zero: $SrcT = Int::zero(); - let max_value: $DstT = Int::max_value(); - if zero <= $slf && $slf as u64 <= max_value as u64 { - Some($slf as $DstT) - } else { - None - } - } - } - ) -} - -macro_rules! impl_to_primitive_uint { - ($T:ty) => ( - impl ToPrimitive for $T { - #[inline] - fn to_int(&self) -> Option { impl_to_primitive_uint_to_int!(isize, *self) } - #[inline] - fn to_isize(&self) -> Option { impl_to_primitive_uint_to_int!(isize, *self) } - #[inline] - fn to_i8(&self) -> Option { impl_to_primitive_uint_to_int!(i8, *self) } - #[inline] - fn to_i16(&self) -> Option { impl_to_primitive_uint_to_int!(i16, *self) } - #[inline] - fn to_i32(&self) -> Option { impl_to_primitive_uint_to_int!(i32, *self) } - #[inline] - fn to_i64(&self) -> Option { impl_to_primitive_uint_to_int!(i64, *self) } - - #[inline] - fn to_uint(&self) -> Option { impl_to_primitive_uint_to_uint!($T, usize, *self) } - #[inline] - fn to_usize(&self) -> Option { - impl_to_primitive_uint_to_uint!($T, usize, *self) - } - #[inline] - fn to_u8(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u8, *self) } - #[inline] - fn to_u16(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u16, *self) } - #[inline] - fn to_u32(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u32, *self) } - #[inline] - fn to_u64(&self) -> Option { impl_to_primitive_uint_to_uint!($T, u64, *self) } - - #[inline] - fn to_f32(&self) -> Option { Some(*self as f32) } - #[inline] - fn to_f64(&self) -> Option { Some(*self as f64) } - } - ) -} - -impl_to_primitive_uint! { usize } -impl_to_primitive_uint! { u8 } -impl_to_primitive_uint! { u16 } -impl_to_primitive_uint! { u32 } -impl_to_primitive_uint! { u64 } - -macro_rules! impl_to_primitive_float_to_float { - ($SrcT:ident, $DstT:ident, $slf:expr) => ( - if size_of::<$SrcT>() <= size_of::<$DstT>() { - Some($slf as $DstT) - } else { - let n = $slf as f64; - let max_value: $SrcT = ::$SrcT::MAX; - if -max_value as f64 <= n && n <= max_value as f64 { - Some($slf as $DstT) - } else { - None - } - } - ) -} - -macro_rules! impl_to_primitive_float { - ($T:ident) => ( - impl ToPrimitive for $T { - #[inline] - fn to_int(&self) -> Option { Some(*self as isize) } - #[inline] - fn to_isize(&self) -> Option { Some(*self as isize) } - #[inline] - fn to_i8(&self) -> Option { Some(*self as i8) } - #[inline] - fn to_i16(&self) -> Option { Some(*self as i16) } - #[inline] - fn to_i32(&self) -> Option { Some(*self as i32) } - #[inline] - fn to_i64(&self) -> Option { Some(*self as i64) } - - #[inline] - fn to_uint(&self) -> Option { Some(*self as usize) } - #[inline] - fn to_usize(&self) -> Option { Some(*self as usize) } - #[inline] - fn to_u8(&self) -> Option { Some(*self as u8) } - #[inline] - fn to_u16(&self) -> Option { Some(*self as u16) } - #[inline] - fn to_u32(&self) -> Option { Some(*self as u32) } - #[inline] - fn to_u64(&self) -> Option { Some(*self as u64) } - - #[inline] - fn to_f32(&self) -> Option { impl_to_primitive_float_to_float!($T, f32, *self) } - #[inline] - fn to_f64(&self) -> Option { impl_to_primitive_float_to_float!($T, f64, *self) } - } - ) -} - -impl_to_primitive_float! { f32 } -impl_to_primitive_float! { f64 } - -/// A generic trait for converting a number to a value. -#[unstable(feature = "core", reason = "trait is likely to be removed")] -pub trait FromPrimitive : ::marker::Sized { - /// Convert an `isize` to return an optional value of this type. If the - /// value cannot be represented by this value, the `None` is returned. - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", reason = "use from_isize")] - fn from_int(n: isize) -> Option { - FromPrimitive::from_i64(n as i64) - } - - /// Convert an `isize` to return an optional value of this type. If the - /// value cannot be represented by this value, the `None` is returned. - #[inline] - fn from_isize(n: isize) -> Option { - FromPrimitive::from_i64(n as i64) - } - - /// Convert an `i8` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_i8(n: i8) -> Option { - FromPrimitive::from_i64(n as i64) - } - - /// Convert an `i16` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_i16(n: i16) -> Option { - FromPrimitive::from_i64(n as i64) - } - - /// Convert an `i32` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_i32(n: i32) -> Option { - FromPrimitive::from_i64(n as i64) - } - - /// Convert an `i64` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - fn from_i64(n: i64) -> Option; - - /// Convert an `usize` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", reason = "use from_usize")] - fn from_uint(n: usize) -> Option { - FromPrimitive::from_u64(n as u64) - } - - /// Convert a `usize` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_usize(n: usize) -> Option { - FromPrimitive::from_u64(n as u64) - } - - /// Convert an `u8` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_u8(n: u8) -> Option { - FromPrimitive::from_u64(n as u64) - } - - /// Convert an `u16` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_u16(n: u16) -> Option { - FromPrimitive::from_u64(n as u64) - } - - /// Convert an `u32` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_u32(n: u32) -> Option { - FromPrimitive::from_u64(n as u64) - } - - /// Convert an `u64` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - fn from_u64(n: u64) -> Option; - - /// Convert a `f32` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_f32(n: f32) -> Option { - FromPrimitive::from_f64(n as f64) - } - - /// Convert a `f64` to return an optional value of this type. If the - /// type cannot be represented by this value, the `None` is returned. - #[inline] - fn from_f64(n: f64) -> Option { - FromPrimitive::from_i64(n as i64) - } -} - -/// A utility function that just calls `FromPrimitive::from_int`. -#[unstable(feature = "core", reason = "likely to be removed")] -#[deprecated(since = "1.0.0", reason = "use from_isize")] -pub fn from_int(n: isize) -> Option { - FromPrimitive::from_isize(n) -} - -/// A utility function that just calls `FromPrimitive::from_isize`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_isize(n: isize) -> Option { - FromPrimitive::from_isize(n) -} - -/// A utility function that just calls `FromPrimitive::from_i8`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_i8(n: i8) -> Option { - FromPrimitive::from_i8(n) -} - -/// A utility function that just calls `FromPrimitive::from_i16`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_i16(n: i16) -> Option { - FromPrimitive::from_i16(n) -} - -/// A utility function that just calls `FromPrimitive::from_i32`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_i32(n: i32) -> Option { - FromPrimitive::from_i32(n) -} - -/// A utility function that just calls `FromPrimitive::from_i64`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_i64(n: i64) -> Option { - FromPrimitive::from_i64(n) -} - -/// A utility function that just calls `FromPrimitive::from_uint`. -#[unstable(feature = "core", reason = "likely to be removed")] -#[deprecated(since = "1.0.0", reason = "use from_uint")] -pub fn from_uint(n: usize) -> Option { - FromPrimitive::from_usize(n) -} - -/// A utility function that just calls `FromPrimitive::from_usize`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_usize(n: usize) -> Option { - FromPrimitive::from_usize(n) -} - -/// A utility function that just calls `FromPrimitive::from_u8`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_u8(n: u8) -> Option { - FromPrimitive::from_u8(n) -} - -/// A utility function that just calls `FromPrimitive::from_u16`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_u16(n: u16) -> Option { - FromPrimitive::from_u16(n) -} - -/// A utility function that just calls `FromPrimitive::from_u32`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_u32(n: u32) -> Option { - FromPrimitive::from_u32(n) -} - -/// A utility function that just calls `FromPrimitive::from_u64`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_u64(n: u64) -> Option { - FromPrimitive::from_u64(n) -} - -/// A utility function that just calls `FromPrimitive::from_f32`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_f32(n: f32) -> Option { - FromPrimitive::from_f32(n) -} - -/// A utility function that just calls `FromPrimitive::from_f64`. -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn from_f64(n: f64) -> Option { - FromPrimitive::from_f64(n) -} - -macro_rules! impl_from_primitive { - ($T:ty, $to_ty:ident) => ( - #[allow(deprecated)] - impl FromPrimitive for $T { - #[inline] fn from_int(n: isize) -> Option<$T> { n.$to_ty() } - #[inline] fn from_i8(n: i8) -> Option<$T> { n.$to_ty() } - #[inline] fn from_i16(n: i16) -> Option<$T> { n.$to_ty() } - #[inline] fn from_i32(n: i32) -> Option<$T> { n.$to_ty() } - #[inline] fn from_i64(n: i64) -> Option<$T> { n.$to_ty() } - - #[inline] fn from_uint(n: usize) -> Option<$T> { n.$to_ty() } - #[inline] fn from_u8(n: u8) -> Option<$T> { n.$to_ty() } - #[inline] fn from_u16(n: u16) -> Option<$T> { n.$to_ty() } - #[inline] fn from_u32(n: u32) -> Option<$T> { n.$to_ty() } - #[inline] fn from_u64(n: u64) -> Option<$T> { n.$to_ty() } - - #[inline] fn from_f32(n: f32) -> Option<$T> { n.$to_ty() } - #[inline] fn from_f64(n: f64) -> Option<$T> { n.$to_ty() } - } - ) -} - -impl_from_primitive! { isize, to_int } -impl_from_primitive! { i8, to_i8 } -impl_from_primitive! { i16, to_i16 } -impl_from_primitive! { i32, to_i32 } -impl_from_primitive! { i64, to_i64 } -impl_from_primitive! { usize, to_uint } -impl_from_primitive! { u8, to_u8 } -impl_from_primitive! { u16, to_u16 } -impl_from_primitive! { u32, to_u32 } -impl_from_primitive! { u64, to_u64 } -impl_from_primitive! { f32, to_f32 } -impl_from_primitive! { f64, to_f64 } - -/// Cast from one machine scalar to another. -/// -/// # Examples -/// -/// ``` -/// # #![feature(core)] -/// use std::num; -/// -/// let twenty: f32 = num::cast(0x14).unwrap(); -/// assert_eq!(twenty, 20f32); -/// ``` -/// -#[inline] -#[unstable(feature = "core", reason = "likely to be removed")] -pub fn cast(n: T) -> Option { - NumCast::from(n) -} - -/// An interface for casting between machine scalars. -#[unstable(feature = "core", reason = "trait is likely to be removed")] -pub trait NumCast: ToPrimitive { - /// Creates a number from another value that can be converted into a primitive via the - /// `ToPrimitive` trait. - fn from(n: T) -> Option; -} - -macro_rules! impl_num_cast { - ($T:ty, $conv:ident) => ( - impl NumCast for $T { - #[inline] - #[allow(deprecated)] - fn from(n: N) -> Option<$T> { - // `$conv` could be generated using `concat_idents!`, but that - // macro seems to be broken at the moment - n.$conv() - } - } - ) -} - -impl_num_cast! { u8, to_u8 } -impl_num_cast! { u16, to_u16 } -impl_num_cast! { u32, to_u32 } -impl_num_cast! { u64, to_u64 } -impl_num_cast! { usize, to_uint } -impl_num_cast! { i8, to_i8 } -impl_num_cast! { i16, to_i16 } -impl_num_cast! { i32, to_i32 } -impl_num_cast! { i64, to_i64 } -impl_num_cast! { isize, to_int } -impl_num_cast! { f32, to_f32 } -impl_num_cast! { f64, to_f64 } - /// Used for representing the classification of floating point numbers #[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] @@ -2469,92 +1120,22 @@ pub enum FpCategory { } /// A built-in floating point number. -// FIXME(#5527): In a future version of Rust, many of these functions will -// become constants. -// -// FIXME(#8888): Several of these functions have a parameter named -// `unused_self`. Removing it requires #8888 to be fixed. -#[unstable(feature = "core", - reason = "distribution of methods between core/std is unclear")] -pub trait Float - : Copy + Clone - + NumCast - + PartialOrd - + PartialEq - + Neg - + Add - + Sub - + Mul - + Div - + Rem -{ +#[doc(hidden)] +pub trait Float { /// Returns the NaN value. fn nan() -> Self; /// Returns the infinite value. fn infinity() -> Self; /// Returns the negative infinite value. fn neg_infinity() -> Self; - /// Returns the `0` value. - fn zero() -> Self; /// Returns -0.0. fn neg_zero() -> Self; - /// Returns the `1` value. + /// Returns 0.0. + fn zero() -> Self; + /// Returns 1.0. fn one() -> Self; - - // FIXME (#5527): These should be associated constants - - /// Returns the number of binary digits of mantissa that this type supports. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MANTISSA_DIGITS` or \ - `std::f64::MANTISSA_DIGITS` as appropriate")] - fn mantissa_digits(unused_self: Option) -> usize; - /// Returns the number of base-10 digits of precision that this type supports. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::DIGITS` or `std::f64::DIGITS` as appropriate")] - fn digits(unused_self: Option) -> usize; - /// Returns the difference between 1.0 and the smallest representable number larger than 1.0. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::EPSILON` or `std::f64::EPSILON` as appropriate")] - fn epsilon() -> Self; - /// Returns the minimum binary exponent that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN_EXP` or `std::f64::MIN_EXP` as appropriate")] - fn min_exp(unused_self: Option) -> isize; - /// Returns the maximum binary exponent that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MAX_EXP` or `std::f64::MAX_EXP` as appropriate")] - fn max_exp(unused_self: Option) -> isize; - /// Returns the minimum base-10 exponent that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN_10_EXP` or `std::f64::MIN_10_EXP` as appropriate")] - fn min_10_exp(unused_self: Option) -> isize; - /// Returns the maximum base-10 exponent that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MAX_10_EXP` or `std::f64::MAX_10_EXP` as appropriate")] - fn max_10_exp(unused_self: Option) -> isize; - /// Returns the smallest finite value that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN` or `std::f64::MIN` as appropriate")] - fn min_value() -> Self; - /// Returns the smallest normalized positive number that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN_POSITIVE` or \ - `std::f64::MIN_POSITIVE` as appropriate")] - fn min_pos_value(unused_self: Option) -> Self; - /// Returns the largest finite value that this type can represent. - #[unstable(feature = "core")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MAX` or `std::f64::MAX` as appropriate")] - fn max_value() -> Self; + /// Parses the string `s` with the radix `r` as a float. + fn from_str_radix(s: &str, r: u32) -> Result; /// Returns true if this value is NaN and false otherwise. fn is_nan(self) -> bool; @@ -2639,38 +1220,13 @@ pub trait Float fn to_radians(self) -> Self; } -/// A generic trait for converting a string with a radix (base) to a value -#[unstable(feature = "core", reason = "needs reevaluation")] -#[deprecated(since = "1.0.0", - reason = "moved to inherent methods; use e.g. i32::from_str_radix")] -pub trait FromStrRadix { - #[unstable(feature = "core", reason = "needs reevaluation")] - #[deprecated(since = "1.0.0", reason = "moved to inherent methods")] - type Err; - - #[unstable(feature = "core", reason = "needs reevaluation")] - #[deprecated(since = "1.0.0", - reason = "moved to inherent methods; use e.g. i32::from_str_radix")] - #[allow(deprecated)] - fn from_str_radix(str: &str, radix: u32) -> Result; -} - -/// A utility function that just calls `FromStrRadix::from_str_radix`. -#[unstable(feature = "core", reason = "needs reevaluation")] -#[deprecated(since = "1.0.0", reason = "use e.g. i32::from_str_radix")] -#[allow(deprecated)] -pub fn from_str_radix(str: &str, radix: u32) - -> Result { - FromStrRadix::from_str_radix(str, radix) -} - -macro_rules! from_str_radix_float_impl { - ($T:ty) => { +macro_rules! from_str_float_impl { + ($T:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for $T { type Err = ParseFloatError; - /// Convert a string in base 10 to a float. + /// Converts a string in base 10 to a float. /// Accepts an optional decimal exponent. /// /// This function accepts strings such as @@ -2693,266 +1249,113 @@ macro_rules! from_str_radix_float_impl { /// /// # Return value /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. + /// `Err(ParseFloatError)` if the string did not represent a valid + /// number. Otherwise, `Ok(n)` where `n` is the floating-point + /// number represented by `src`. #[inline] #[allow(deprecated)] fn from_str(src: &str) -> Result<$T, ParseFloatError> { - from_str_radix(src, 10) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl FromStrRadix for $T { - type Err = ParseFloatError; - - /// Convert a string in a given base to a float. - /// - /// Due to possible conflicts, this function does **not** accept - /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - /// does it recognize exponents of any kind. - /// - /// Leading and trailing whitespace represent an error. - /// - /// # Arguments - /// - /// * src - A string - /// * radix - The base to use. Must lie in the range [2 .. 36] - /// - /// # Return value - /// - /// `None` if the string did not represent a valid number. - /// Otherwise, `Some(n)` where `n` is the floating-point number - /// represented by `src`. - fn from_str_radix(src: &str, radix: u32) - -> Result<$T, ParseFloatError> { - use self::FloatErrorKind::*; - use self::ParseFloatError as PFE; - assert!(radix >= 2 && radix <= 36, - "from_str_radix_float: must lie in the range `[2, 36]` - found {}", - radix); - - // Special values - match src { - "inf" => return Ok(Float::infinity()), - "-inf" => return Ok(Float::neg_infinity()), - "NaN" => return Ok(Float::nan()), - _ => {}, - } - - let (is_positive, src) = match src.slice_shift_char() { - None => return Err(PFE { kind: Empty }), - Some(('-', "")) => return Err(PFE { kind: Empty }), - Some(('-', src)) => (false, src), - Some((_, _)) => (true, src), - }; - - // The significand to accumulate - let mut sig = if is_positive { 0.0 } else { -0.0 }; - // Necessary to detect overflow - let mut prev_sig = sig; - let mut cs = src.chars().enumerate(); - // Exponent prefix and exponent index offset - let mut exp_info = None::<(char, usize)>; - - // Parse the integer part of the significand - for (i, c) in cs.by_ref() { - match c.to_digit(radix) { - Some(digit) => { - // shift significand one digit left - sig = sig * (radix as $T); - - // add/subtract current digit depending on sign - if is_positive { - sig = sig + ((digit as isize) as $T); - } else { - sig = sig - ((digit as isize) as $T); - } - - // Detect overflow by comparing to last value, except - // if we've not seen any non-zero digits. - if prev_sig != 0.0 { - if is_positive && sig <= prev_sig - { return Ok(Float::infinity()); } - if !is_positive && sig >= prev_sig - { return Ok(Float::neg_infinity()); } - - // Detect overflow by reversing the shift-and-add process - if is_positive && (prev_sig != (sig - digit as $T) / radix as $T) - { return Ok(Float::infinity()); } - if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T) - { return Ok(Float::neg_infinity()); } - } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - '.' => { - break; // start of fractional part - }, - _ => { - return Err(PFE { kind: Invalid }); - }, - }, - } - } - - // If we are not yet at the exponent parse the fractional - // part of the significand - if exp_info.is_none() { - let mut power = 1.0; - for (i, c) in cs.by_ref() { - match c.to_digit(radix) { - Some(digit) => { - // Decrease power one order of magnitude - power = power / (radix as $T); - // add/subtract current digit depending on sign - sig = if is_positive { - sig + (digit as $T) * power - } else { - sig - (digit as $T) * power - }; - // Detect overflow by comparing to last value - if is_positive && sig < prev_sig - { return Ok(Float::infinity()); } - if !is_positive && sig > prev_sig - { return Ok(Float::neg_infinity()); } - prev_sig = sig; - }, - None => match c { - 'e' | 'E' | 'p' | 'P' => { - exp_info = Some((c, i + 1)); - break; // start of exponent - }, - _ => { - return Err(PFE { kind: Invalid }); - }, - }, - } - } - } - - // Parse and calculate the exponent - let exp = match exp_info { - Some((c, offset)) => { - let base = match c { - 'E' | 'e' if radix == 10 => 10.0, - 'P' | 'p' if radix == 16 => 2.0, - _ => return Err(PFE { kind: Invalid }), - }; - - // Parse the exponent as decimal integer - let src = &src[offset..]; - let (is_positive, exp) = match src.slice_shift_char() { - Some(('-', src)) => (false, src.parse::()), - Some(('+', src)) => (true, src.parse::()), - Some((_, _)) => (true, src.parse::()), - None => return Err(PFE { kind: Invalid }), - }; - - match (is_positive, exp) { - (true, Ok(exp)) => base.powi(exp as i32), - (false, Ok(exp)) => 1.0 / base.powi(exp as i32), - (_, Err(_)) => return Err(PFE { kind: Invalid }), - } - }, - None => 1.0, // no exponent - }; - - Ok(sig * exp) + $T::from_str_radix(src, 10) } } } } -from_str_radix_float_impl! { f32 } -from_str_radix_float_impl! { f64 } +from_str_float_impl!(f32); +from_str_float_impl!(f64); macro_rules! from_str_radix_int_impl { - ($T:ty) => { + ($($T:ident)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] impl FromStr for $T { type Err = ParseIntError; - #[inline] fn from_str(src: &str) -> Result<$T, ParseIntError> { from_str_radix(src, 10) } } + )*} +} +from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 } - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl FromStrRadix for $T { - type Err = ParseIntError; - fn from_str_radix(src: &str, radix: u32) - -> Result<$T, ParseIntError> { - 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); - - let is_signed_ty = (0 as $T) > Int::min_value(); - - match src.slice_shift_char() { - Some(('-', "")) => Err(PIE { kind: Empty }), - Some(('-', src)) if is_signed_ty => { - // The number is negative - let mut result = 0; - for c in src.chars() { - let x = match c.to_digit(radix) { - Some(x) => x, - None => return Err(PIE { kind: InvalidDigit }), - }; - result = match result.checked_mul(radix as $T) { - Some(result) => result, - None => return Err(PIE { kind: Underflow }), - }; - result = match result.checked_sub(x as $T) { - Some(result) => result, - None => return Err(PIE { kind: Underflow }), - }; - } - Ok(result) - }, - Some((_, _)) => { - // The number is signed - let mut result = 0; - for c in src.chars() { - let x = match c.to_digit(radix) { - Some(x) => x, - None => return Err(PIE { kind: InvalidDigit }), - }; - result = match result.checked_mul(radix as $T) { - Some(result) => result, - None => return Err(PIE { kind: Overflow }), - }; - result = match result.checked_add(x as $T) { - Some(result) => result, - None => return Err(PIE { kind: Overflow }), - }; - } - Ok(result) - }, - None => Err(ParseIntError { kind: Empty }), - } - } +#[doc(hidden)] +trait FromStrRadixHelper: PartialOrd + Copy { + fn min_value() -> Self; + fn from_u32(u: u32) -> Self; + fn checked_mul(&self, other: u32) -> Option; + fn checked_sub(&self, other: u32) -> Option; + fn checked_add(&self, other: u32) -> Option; +} + +macro_rules! doit { + ($($t:ident)*) => ($(impl FromStrRadixHelper for $t { + fn min_value() -> Self { <$t>::min_value() } + fn from_u32(u: u32) -> Self { u as $t } + fn checked_mul(&self, other: u32) -> Option { + <$t>::checked_mul(*self, other as $t) } + fn checked_sub(&self, other: u32) -> Option { + <$t>::checked_sub(*self, other as $t) + } + fn checked_add(&self, other: u32) -> Option { + <$t>::checked_add(*self, other as $t) + } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +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); + + 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 => { + // The number is negative + let mut result = T::from_u32(0); + for c in src.chars() { + let x = match c.to_digit(radix) { + Some(x) => x, + None => return Err(PIE { kind: InvalidDigit }), + }; + result = match result.checked_mul(radix) { + Some(result) => result, + None => return Err(PIE { kind: Underflow }), + }; + result = match result.checked_sub(x) { + Some(result) => result, + None => return Err(PIE { kind: Underflow }), + }; + } + Ok(result) + }, + Some((_, _)) => { + // The number is signed + let mut result = T::from_u32(0); + for c in src.chars() { + let x = match c.to_digit(radix) { + Some(x) => x, + None => return Err(PIE { kind: InvalidDigit }), + }; + result = match result.checked_mul(radix) { + Some(result) => result, + None => return Err(PIE { kind: Overflow }), + }; + result = match result.checked_add(x) { + Some(result) => result, + None => return Err(PIE { kind: Overflow }), + }; + } + Ok(result) + }, + None => Err(ParseIntError { kind: Empty }), } } -from_str_radix_int_impl! { isize } -from_str_radix_int_impl! { i8 } -from_str_radix_int_impl! { i16 } -from_str_radix_int_impl! { i32 } -from_str_radix_int_impl! { i64 } -from_str_radix_int_impl! { usize } -from_str_radix_int_impl! { u8 } -from_str_radix_int_impl! { u16 } -from_str_radix_int_impl! { u32 } -from_str_radix_int_impl! { u64 } /// An error which can be returned when parsing an integer. #[derive(Debug, Clone, PartialEq)] @@ -2988,11 +1391,10 @@ impl fmt::Display for ParseIntError { /// An error which can be returned when parsing a float. #[derive(Debug, Clone, PartialEq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseFloatError { kind: FloatErrorKind } +pub struct ParseFloatError { pub kind: FloatErrorKind } #[derive(Debug, Clone, PartialEq)] -enum FloatErrorKind { +pub enum FloatErrorKind { Empty, Invalid, } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index d0c4885ad0..8678295074 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -13,9 +13,9 @@ macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => ( #[unstable(feature = "core")] -pub const BITS : u32 = $bits; +pub const BITS : usize = $bits; #[unstable(feature = "core")] -pub const BYTES : u32 = ($bits / 8); +pub const BYTES : usize = ($bits / 8); #[stable(feature = "rust1", since = "1.0.0")] pub const MIN: $T = 0 as $T; diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 28276d0bf0..28c877872e 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -15,8 +15,6 @@ use super::Wrapping; use ops::*; -use intrinsics::{overflowing_add, overflowing_sub, overflowing_mul}; - use intrinsics::{i8_add_with_overflow, u8_add_with_overflow}; use intrinsics::{i16_add_with_overflow, u16_add_with_overflow}; use intrinsics::{i32_add_with_overflow, u32_add_with_overflow}; @@ -32,14 +30,6 @@ use intrinsics::{i64_mul_with_overflow, u64_mul_with_overflow}; use ::{i8,i16,i32,i64}; -#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")] -#[deprecated(since = "1.0.0", reason = "moved to inherent methods")] -pub trait WrappingOps { - fn wrapping_add(self, rhs: Self) -> Self; - fn wrapping_sub(self, rhs: Self) -> Self; - fn wrapping_mul(self, rhs: Self) -> Self; -} - #[unstable(feature = "core", reason = "may be removed, renamed, or relocated")] pub trait OverflowingOps { fn overflowing_add(self, rhs: Self) -> (Self, bool); @@ -98,27 +88,6 @@ sh_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } macro_rules! wrapping_impl { ($($t:ty)*) => ($( - impl WrappingOps for $t { - #[inline(always)] - fn wrapping_add(self, rhs: $t) -> $t { - unsafe { - overflowing_add(self, rhs) - } - } - #[inline(always)] - fn wrapping_sub(self, rhs: $t) -> $t { - unsafe { - overflowing_sub(self, rhs) - } - } - #[inline(always)] - fn wrapping_mul(self, rhs: $t) -> $t { - unsafe { - overflowing_mul(self, rhs) - } - } - } - #[stable(feature = "rust1", since = "1.0.0")] impl Add for Wrapping<$t> { type Output = Wrapping<$t>; diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index faf305c6a1..00039c4fcd 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -172,13 +172,13 @@ macro_rules! forward_ref_binop { /// type Output = Foo; /// /// fn add(self, _rhs: Foo) -> Foo { -/// println!("Adding!"); -/// self -/// } +/// println!("Adding!"); +/// self +/// } /// } /// /// fn main() { -/// Foo + Foo; +/// Foo + Foo; /// } /// ``` #[lang="add"] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 6db7c9bd99..d1bc24bd9b 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -223,7 +223,7 @@ impl Option { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Convert from `Option` to `Option<&T>` + /// Converts from `Option` to `Option<&T>` /// /// # Examples /// @@ -248,7 +248,7 @@ impl Option { } } - /// Convert from `Option` to `Option<&mut T>` + /// Converts from `Option` to `Option<&mut T>` /// /// # Examples /// @@ -269,7 +269,7 @@ impl Option { } } - /// Convert from `Option` to `&mut [T]` (without copying) + /// Converts from `Option` to `&mut [T]` (without copying) /// /// # Examples /// @@ -551,25 +551,6 @@ impl Option { IterMut { inner: Item { opt: self.as_mut() } } } - /// Returns a consuming iterator over the possibly contained value. - /// - /// # Examples - /// - /// ``` - /// let x = Some("string"); - /// let v: Vec<&str> = x.into_iter().collect(); - /// assert_eq!(v, ["string"]); - /// - /// let x = None; - /// let v: Vec<&str> = x.into_iter().collect(); - /// assert!(v.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - IntoIter { inner: Item { opt: self } } - } - ///////////////////////////////////////////////////////////////////////// // Boolean operations on the values, eager and lazy ///////////////////////////////////////////////////////////////////////// @@ -704,7 +685,7 @@ impl Option { mem::replace(self, None) } - /// Convert from `Option` to `&[T]` (without copying) + /// Converts from `Option` to `&[T]` (without copying) #[inline] #[unstable(feature = "as_slice", since = "unsure of the utility here")] pub fn as_slice<'a>(&'a self) -> &'a [T] { @@ -770,6 +751,30 @@ impl Default for Option { fn default() -> Option { None } } +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for Option { + type Item = T; + type IntoIter = IntoIter; + + /// Returns a consuming iterator over the possibly contained value. + /// + /// # Examples + /// + /// ``` + /// let x = Some("string"); + /// let v: Vec<&str> = x.into_iter().collect(); + /// assert_eq!(v, ["string"]); + /// + /// let x = None; + /// let v: Vec<&str> = x.into_iter().collect(); + /// assert!(v.is_empty()); + /// ``` + #[inline] + fn into_iter(self) -> IntoIter { + IntoIter { inner: Item { opt: self } } + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index d6e00df1fd..0b8a52329d 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -16,7 +16,7 @@ //! interface for panicking is: //! //! ```ignore -//! fn panic_impl(fmt: fmt::Arguments, &(&'static str, usize)) -> !; +//! fn panic_impl(fmt: fmt::Arguments, &(&'static str, u32)) -> !; //! ``` //! //! This definition allows for panicking with any general message, but it does not @@ -58,8 +58,8 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: usize) -> !; + fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !; } let (file, line) = *file_line; - unsafe { panic_impl(fmt, file, line as usize) } + unsafe { panic_impl(fmt, file, line) } } diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index e60bc49408..a4d529ad47 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -37,11 +37,10 @@ pub use char::CharExt; pub use clone::Clone; pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; pub use convert::{AsRef, AsMut, Into, From}; +pub use default::Default; +pub use iter::IntoIterator; pub use iter::{Iterator, DoubleEndedIterator, Extend, ExactSizeIterator}; pub use option::Option::{self, Some, None}; pub use result::Result::{self, Ok, Err}; pub use slice::SliceExt; pub use str::StrExt; - -#[allow(deprecated)] pub use slice::AsSlice; -#[allow(deprecated)] pub use str::Str; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index ff51e25fcb..0e9570df09 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -15,9 +15,9 @@ //! Working with unsafe pointers in Rust is uncommon, //! typically limited to a few patterns. //! -//! Use the [`null` function](fn.null.html) 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. +//! 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 unsafe pointers //! @@ -89,11 +89,13 @@ //! of unsafe pointers in Rust. #![stable(feature = "rust1", since = "1.0.0")] +#![doc(primitive = "pointer")] use mem; use clone::Clone; use intrinsics; use ops::Deref; +use core::fmt; use option::Option::{self, Some, None}; use marker::{PhantomData, Send, Sized, Sync}; use nonzero::NonZero; @@ -542,19 +544,19 @@ unsafe impl Send for Unique { } unsafe impl Sync for Unique { } impl Unique { - /// Create a new `Unique`. + /// Creates a new `Unique`. #[unstable(feature = "unique")] pub unsafe fn new(ptr: *mut T) -> Unique { Unique { pointer: NonZero::new(ptr), _marker: PhantomData } } - /// Dereference the content. + /// Dereferences the content. #[unstable(feature = "unique")] pub unsafe fn get(&self) -> &T { &**self.pointer } - /// Mutably dereference the content. + /// Mutably dereferences the content. #[unstable(feature = "unique")] pub unsafe fn get_mut(&mut self) -> &mut T { &mut ***self @@ -570,3 +572,10 @@ impl Deref for Unique { unsafe { mem::transmute(&*self.pointer) } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Unique { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&*self.pointer, f) + } +} diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index ded52ff077..685b3e5c54 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -71,11 +71,11 @@ impl Clone for Slice { /// The representation of a trait object like `&SomeTrait`. /// /// This struct has the same layout as types like `&SomeTrait` and -/// `Box`. The [Static and Dynamic Dispatch chapter of the +/// `Box`. The [Trait Objects chapter of the /// Book][moreinfo] contains more details about the precise nature of /// these internals. /// -/// [moreinfo]: ../../book/static-and-dynamic-dispatch.html#representation +/// [moreinfo]: ../../book/trait-objects.html#representation /// /// `TraitObject` is guaranteed to match layouts, but it is not the /// type of trait objects (e.g. the fields are not directly accessible diff --git a/src/libcore/result.rs b/src/libcore/result.rs index eff04dd590..e909946ece 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -34,24 +34,18 @@ //! enum Version { Version1, Version2 } //! //! fn parse_version(header: &[u8]) -> Result { -//! if header.len() < 1 { -//! return Err("invalid header length"); -//! } -//! match header[0] { -//! 1 => Ok(Version::Version1), -//! 2 => Ok(Version::Version2), -//! _ => Err("invalid version") +//! match header.get(0) { +//! None => Err("invalid header length"), +//! Some(&1) => Ok(Version::Version1), +//! Some(&2) => Ok(Version::Version2), +//! Some(_) => Err("invalid version") //! } //! } //! //! let version = parse_version(&[1, 2, 3, 4]); //! match version { -//! Ok(v) => { -//! println!("working with version: {:?}", v); -//! } -//! Err(e) => { -//! println!("error parsing header: {:?}", e); -//! } +//! Ok(v) => println!("working with version: {:?}", v), +//! Err(e) => println!("error parsing header: {:?}", e), //! } //! ``` //! @@ -75,7 +69,7 @@ //! let good_result: Result = good_result.and_then(|i| Ok(i == 11)); //! //! // Use `or_else` to handle the error. -//! let bad_result: Result = bad_result.or_else(|i| Ok(11)); +//! let bad_result: Result = bad_result.or_else(|i| Ok(i + 20)); //! //! // Consume the result and return the contents with `unwrap`. //! let final_awesome_result = good_result.unwrap(); @@ -91,35 +85,32 @@ //! functions that may encounter errors but don't otherwise return a //! useful value. //! -//! Consider the `write_line` method defined for I/O types -//! by the [`Writer`](../old_io/trait.Writer.html) trait: +//! Consider the `write_all` method defined for I/O types +//! by the [`Write`](../../std/io/trait.Write.html) trait: //! //! ``` -//! # #![feature(old_io)] -//! use std::old_io::IoError; +//! use std::io; //! -//! trait Writer { -//! fn write_line(&mut self, s: &str) -> Result<(), IoError>; +//! trait Write { +//! fn write_all(&mut self, bytes: &[u8]) -> Result<(), io::Error>; //! } //! ``` //! -//! *Note: The actual definition of `Writer` uses `IoResult`, which -//! is just a synonym for `Result`.* +//! *Note: The actual definition of `Write` uses `io::Result`, which +//! is just a synonym for `Result`.* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write //! something like this: //! -//! ```{.ignore} -//! # #![feature(old_io)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! ```no_run +//! use std::fs::File; +//! use std::io::prelude::*; //! -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! // If `write_line` errors, then we'll never know, because the return +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! // If `write_all` errors, then we'll never know, because the return //! // value is ignored. -//! file.write_line("important message"); -//! drop(file); +//! file.write_all(b"important message"); //! ``` //! //! If you *do* write that in Rust, the compiler will give you a @@ -131,38 +122,32 @@ //! a marginally useful message indicating why: //! //! ```{.no_run} -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; //! -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! file.write_line("important message").ok().expect("failed to write message"); -//! drop(file); +//! let mut file = File::create("valuable_data.txt").unwrap(); +//! file.write_all(b"important message").ok().expect("failed to write message"); //! ``` //! //! You might also simply assert success: //! //! ```{.no_run} -//! # #![feature(old_io, old_path)] -//! # use std::old_io::*; -//! # use std::old_path::Path; -//! -//! # let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! assert!(file.write_line("important message").is_ok()); -//! # drop(file); +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # let mut file = File::create("valuable_data.txt").unwrap(); +//! assert!(file.write_all(b"important message").is_ok()); //! ``` //! //! Or propagate the error up the call stack with `try!`: //! //! ``` -//! # #![feature(old_io, old_path)] -//! # use std::old_io::*; -//! # use std::old_path::Path; -//! fn write_message() -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write); -//! try!(file.write_line("important message")); -//! drop(file); -//! return Ok(()); +//! # use std::fs::File; +//! # use std::io::prelude::*; +//! # use std::io; +//! fn write_message() -> io::Result<()> { +//! let mut file = try!(File::create("valuable_data.txt")); +//! try!(file.write_all(b"important message")); +//! Ok(()) //! } //! ``` //! @@ -176,9 +161,9 @@ //! It replaces this: //! //! ``` -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; //! //! struct Info { //! name: String, @@ -186,25 +171,28 @@ //! rating: i32, //! } //! -//! fn write_info(info: &Info) -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write); +//! fn write_info(info: &Info) -> io::Result<()> { +//! let mut file = try!(File::create("my_best_friends.txt")); //! // Early return on error -//! if let Err(e) = file.write_line(&format!("name: {}", info.name)) { +//! if let Err(e) = file.write_all(format!("name: {}\n", info.name).as_bytes()) { //! return Err(e) //! } -//! if let Err(e) = file.write_line(&format!("age: {}", info.age)) { +//! if let Err(e) = file.write_all(format!("age: {}\n", info.age).as_bytes()) { //! return Err(e) //! } -//! return file.write_line(&format!("rating: {}", info.rating)); +//! if let Err(e) = file.write_all(format!("rating: {}\n", info.rating).as_bytes()) { +//! return Err(e) +//! } +//! Ok(()) //! } //! ``` //! //! With this: //! //! ``` -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; +//! use std::fs::File; +//! use std::io::prelude::*; +//! use std::io; //! //! struct Info { //! name: String, @@ -212,13 +200,13 @@ //! rating: i32, //! } //! -//! fn write_info(info: &Info) -> Result<(), IoError> { -//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write); +//! fn write_info(info: &Info) -> io::Result<()> { +//! let mut file = try!(File::create("my_best_friends.txt")); //! // Early return on error -//! try!(file.write_line(&format!("name: {}", info.name))); -//! try!(file.write_line(&format!("age: {}", info.age))); -//! try!(file.write_line(&format!("rating: {}", info.rating))); -//! return Ok(()); +//! try!(file.write_all(format!("name: {}\n", info.name).as_bytes())); +//! try!(file.write_all(format!("age: {}\n", info.age).as_bytes())); +//! try!(file.write_all(format!("rating: {}\n", info.rating).as_bytes())); +//! Ok(()) //! } //! ``` //! @@ -246,8 +234,6 @@ use fmt; use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator}; use ops::{FnMut, FnOnce}; use option::Option::{self, None, Some}; -#[allow(deprecated)] -use slice::AsSlice; use slice; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). @@ -317,7 +303,7 @@ impl Result { // Adapter for each variant ///////////////////////////////////////////////////////////////////////// - /// Convert from `Result` to `Option` + /// Converts from `Result` to `Option` /// /// Converts `self` into an `Option`, consuming `self`, /// and discarding the error, if any. @@ -340,7 +326,7 @@ impl Result { } } - /// Convert from `Result` to `Option` + /// Converts from `Result` to `Option` /// /// Converts `self` into an `Option`, consuming `self`, /// and discarding the success value, if any. @@ -367,7 +353,7 @@ impl Result { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Convert from `Result` to `Result<&T, &E>` + /// Converts from `Result` to `Result<&T, &E>` /// /// Produces a new `Result`, containing a reference /// into the original, leaving the original in place. @@ -388,7 +374,7 @@ impl Result { } } - /// Convert from `Result` to `Result<&mut T, &mut E>` + /// Converts from `Result` to `Result<&mut T, &mut E>` /// /// ``` /// fn mutate(r: &mut Result) { @@ -415,7 +401,7 @@ impl Result { } } - /// Convert from `Result` to `&[T]` (without copying) + /// Converts from `Result` to `&[T]` (without copying) #[inline] #[unstable(feature = "as_slice", since = "unsure of the utility here")] pub fn as_slice(&self) -> &[T] { @@ -429,7 +415,7 @@ impl Result { } } - /// Convert from `Result` to `&mut [T]` (without copying) + /// Converts from `Result` to `&mut [T]` (without copying) /// /// ``` /// # #![feature(core)] @@ -470,29 +456,17 @@ impl Result { /// /// # Examples /// - /// Sum the lines of a buffer by mapping strings to numbers, - /// ignoring I/O and parse errors: + /// Print the numbers on each line of a string multiplied by two. /// /// ``` - /// # #![feature(old_io)] - /// use std::old_io::*; - /// - /// let mut buffer: &[u8] = b"1\n2\n3\n4\n"; - /// let mut buffer = &mut buffer; + /// let line = "1\n2\n3\n4\n"; /// - /// let mut sum = 0; - /// - /// while !buffer.is_empty() { - /// let line: IoResult = buffer.read_line(); - /// // Convert the string line to a number using `map` and `from_str` - /// let val: IoResult = line.map(|line| { - /// line.trim_right().parse::().unwrap_or(0) - /// }); - /// // Add the value if there were no errors, otherwise add 0 - /// sum += val.unwrap_or(0); + /// for num in line.lines() { + /// match num.parse::().map(|i| i * 2) { + /// Ok(n) => println!("{}", n), + /// Err(..) => {} + /// } /// } - /// - /// assert!(sum == 10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -571,25 +545,6 @@ impl Result { IterMut { inner: self.as_mut().ok() } } - /// Returns a consuming iterator over the possibly contained value. - /// - /// # Examples - /// - /// ``` - /// let x: Result = Ok(5); - /// let v: Vec = x.into_iter().collect(); - /// assert_eq!(v, [5]); - /// - /// let x: Result = Err("nothing!"); - /// let v: Vec = x.into_iter().collect(); - /// assert_eq!(v, []); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - IntoIter { inner: self.ok() } - } - //////////////////////////////////////////////////////////////////////// // Boolean operations on the values, eager and lazy ///////////////////////////////////////////////////////////////////////// @@ -751,8 +706,8 @@ impl Result { /// /// # Panics /// - /// Panics if the value is an `Err`, with a custom panic message provided - /// by the `Err`'s value. + /// Panics if the value is an `Err`, with a panic message provided by the + /// `Err`'s value. /// /// # Examples /// @@ -811,23 +766,27 @@ impl Result { // Trait implementations ///////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "core", - reason = "waiting on the stability of the trait itself")] -#[deprecated(since = "1.0.0", - reason = "use inherent method instead")] -#[allow(deprecated)] -impl AsSlice for Result { - /// Convert from `Result` to `&[T]` (without copying) +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for Result { + type Item = T; + type IntoIter = IntoIter; + + /// Returns a consuming iterator over the possibly contained value. + /// + /// # Examples + /// + /// ``` + /// let x: Result = Ok(5); + /// let v: Vec = x.into_iter().collect(); + /// assert_eq!(v, [5]); + /// + /// let x: Result = Err("nothing!"); + /// let v: Vec = x.into_iter().collect(); + /// assert_eq!(v, []); + /// ``` #[inline] - fn as_slice<'a>(&'a self) -> &'a [T] { - match *self { - Ok(ref x) => slice::ref_slice(x), - Err(_) => { - // work around lack of implicit coercion from fixed-size array to slice - let emp: &[_] = &[]; - emp - } - } + fn into_iter(self) -> IntoIter { + IntoIter { inner: self.ok() } } } @@ -980,7 +939,7 @@ impl> FromIterator> for Result { // FromIterator ///////////////////////////////////////////////////////////////////////////// -/// Perform a fold operation over the result values from an iterator. +/// Performs a fold operation over the result values from an iterator. /// /// If an `Err` is encountered, it is immediately returned. /// Otherwise, the folded value is returned. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 70e60adf64..1e96d761d4 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -51,7 +51,7 @@ use result::Result::{Ok, Err}; use ptr; use mem; use mem::size_of; -use marker::{Send, Sized, Sync, self}; +use marker::{Send, Sync, self}; use raw::Repr; // Avoid conflicts with *both* the Slice trait (buggy) and the `slice::raw` module. use raw::Slice as RawSlice; @@ -63,6 +63,7 @@ use raw::Slice as RawSlice; /// Extension methods for slices. #[allow(missing_docs)] // docs in libcollections +#[doc(hidden)] pub trait SliceExt { type Item; @@ -203,7 +204,7 @@ impl SliceExt for [T] { #[inline] fn first(&self) -> Option<&T> { - if self.len() == 0 { None } else { Some(&self[0]) } + if self.is_empty() { None } else { Some(&self[0]) } } #[inline] @@ -216,7 +217,7 @@ impl SliceExt for [T] { #[inline] fn last(&self) -> Option<&T> { - if self.len() == 0 { None } else { Some(&self[self.len() - 1]) } + if self.is_empty() { None } else { Some(&self[self.len() - 1]) } } #[inline] @@ -295,7 +296,7 @@ impl SliceExt for [T] { #[inline] fn first_mut(&mut self) -> Option<&mut T> { - if self.len() == 0 { None } else { Some(&mut self[0]) } + if self.is_empty() { None } else { Some(&mut self[0]) } } #[inline] @@ -594,37 +595,6 @@ impl ops::IndexMut for [T] { // Common traits //////////////////////////////////////////////////////////////////////////////// -/// Data that is viewable as a slice. -#[unstable(feature = "core", - reason = "will be replaced by slice syntax")] -#[deprecated(since = "1.0.0", - reason = "use std::convert::AsRef<[T]> instead")] -pub trait AsSlice { - /// Work with `self` as a slice. - fn as_slice<'a>(&'a self) -> &'a [T]; -} - -#[unstable(feature = "core", reason = "trait is experimental")] -#[allow(deprecated)] -impl AsSlice for [T] { - #[inline(always)] - fn as_slice<'a>(&'a self) -> &'a [T] { self } -} - -#[unstable(feature = "core", reason = "trait is experimental")] -#[allow(deprecated)] -impl<'a, T, U: ?Sized + AsSlice> AsSlice for &'a U { - #[inline(always)] - fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) } -} - -#[unstable(feature = "core", reason = "trait is experimental")] -#[allow(deprecated)] -impl<'a, T, U: ?Sized + AsSlice> AsSlice for &'a mut U { - #[inline(always)] - fn as_slice(&self) -> &[T] { AsSlice::as_slice(*self) } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Default for &'a [T] { #[stable(feature = "rust1", since = "1.0.0")] @@ -1305,7 +1275,7 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[inline] fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() == 0 { + if self.v.is_empty() { None } else { let chunksz = cmp::min(self.v.len(), self.size); @@ -1317,7 +1287,7 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[inline] fn size_hint(&self) -> (usize, Option) { - if self.v.len() == 0 { + if self.v.is_empty() { (0, Some(0)) } else { let n = self.v.len() / self.size; @@ -1332,7 +1302,7 @@ impl<'a, T> Iterator for Chunks<'a, T> { impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() == 0 { + if self.v.is_empty() { None } else { let remainder = self.v.len() % self.size; @@ -1383,7 +1353,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { #[inline] fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() == 0 { + if self.v.is_empty() { None } else { let sz = cmp::min(self.v.len(), self.chunk_size); @@ -1396,7 +1366,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { #[inline] fn size_hint(&self) -> (usize, Option) { - if self.v.len() == 0 { + if self.v.is_empty() { (0, Some(0)) } else { let n = self.v.len() / self.chunk_size; @@ -1411,7 +1381,7 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[inline] fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() == 0 { + if self.v.is_empty() { None } else { let remainder = self.v.len() % self.chunk_size; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dbb365c4e2..31431f4496 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -17,6 +17,8 @@ #![doc(primitive = "str")] use self::OldSearcher::{TwoWay, TwoWayLong}; +use self::pattern::Pattern; +use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::CharExt; use clone::Clone; @@ -25,7 +27,6 @@ use default::Default; use fmt; use iter::ExactSizeIterator; use iter::{Map, Iterator, DoubleEndedIterator}; -use marker::Sized; use mem; use ops::{Fn, FnMut, FnOnce}; use option::Option::{self, None, Some}; @@ -34,100 +35,7 @@ use result::Result::{self, Ok, Err}; use slice::{self, SliceExt}; use usize; -pub use self::pattern::Pattern; -pub use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher, SearchStep}; - -mod pattern; - -macro_rules! delegate_iter { - (exact $te:ty : $ti:ty) => { - delegate_iter!{$te : $ti} - impl<'a> ExactSizeIterator for $ti { - #[inline] - fn len(&self) -> usize { - self.0.len() - } - } - }; - ($te:ty : $ti:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> Iterator for $ti { - type Item = $te; - - #[inline] - fn next(&mut self) -> Option<$te> { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> DoubleEndedIterator for $ti { - #[inline] - fn next_back(&mut self) -> Option<$te> { - self.0.next_back() - } - } - }; - (pattern $te:ty : $ti:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, P: Pattern<'a>> Iterator for $ti { - type Item = $te; - - #[inline] - fn next(&mut self) -> Option<$te> { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, P: Pattern<'a>> DoubleEndedIterator for $ti - where P::Searcher: DoubleEndedSearcher<'a> { - #[inline] - fn next_back(&mut self) -> Option<$te> { - self.0.next_back() - } - } - }; - (pattern forward $te:ty : $ti:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, P: Pattern<'a>> Iterator for $ti - where P::Searcher: DoubleEndedSearcher<'a> { - type Item = $te; - - #[inline] - fn next(&mut self) -> Option<$te> { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - }; - (pattern reverse $te:ty : $ti:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, P: Pattern<'a>> Iterator for $ti - where P::Searcher: ReverseSearcher<'a> - { - type Item = $te; - - #[inline] - fn next(&mut self) -> Option<$te> { - self.0.next() - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - } - }; -} +pub mod pattern; /// A trait to abstract the idea of creating a new instance of a type from a /// string. @@ -197,19 +105,19 @@ Section: Creating a string /// Errors which can occur when attempting to interpret a byte slice as a `str`. #[derive(Copy, Eq, PartialEq, Clone, Debug)] -#[unstable(feature = "core", - reason = "error enumeration recently added and definitions may be refined")] -pub enum Utf8Error { - /// An invalid byte was detected at the byte offset given. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Utf8Error { + valid_up_to: usize, +} + +impl Utf8Error { + /// Returns the index in the given string up to which valid UTF-8 was + /// verified. /// - /// The offset is guaranteed to be in bounds of the slice in question, and - /// the byte at the specified offset was the first invalid byte in the - /// sequence detected. - InvalidByte(usize), - - /// The byte slice was invalid because more bytes were needed but no more - /// bytes were available. - TooShort, + /// Starting at the index provided, but not necessarily at it precisely, an + /// invalid UTF-8 encoding sequence was found. + #[unstable(feature = "utf8_error", reason = "method just added")] + pub fn valid_up_to(&self) -> usize { self.valid_up_to } } /// Converts a slice of bytes to a string slice without performing any @@ -238,14 +146,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Utf8Error::InvalidByte(n) => { - write!(f, "invalid utf-8: invalid byte at index {}", n) - } - Utf8Error::TooShort => { - write!(f, "invalid utf-8: byte slice too short") - } - } + write!(f, "invalid utf-8: invalid byte near index {}", self.valid_up_to) } } @@ -389,8 +290,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { } } -/// External iterator for a string's characters and their byte offsets. -/// Use with the `std::iter` module. +/// Iterator for a string's characters and their byte offsets. #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CharIndices<'a> { @@ -440,15 +340,13 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { /// External iterator for a string's bytes. /// Use with the `std::iter` module. /// -/// Created with `str::bytes` +/// Created with the method `.bytes()`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Bytes<'a>(Map, BytesDeref>); -delegate_iter!{exact u8 : Bytes<'a>} -/// A temporary fn new type that ensures that the `Bytes` iterator -/// is cloneable. -#[derive(Copy, Clone)] +/// A nameable, clonable fn type +#[derive(Clone)] struct BytesDeref; impl<'a> Fn<(&'a u8,)> for BytesDeref { @@ -474,58 +372,210 @@ impl<'a> FnOnce<(&'a u8,)> for BytesDeref { } } -/// An iterator over the substrings of a string, separated by `sep`. -struct CharSplits<'a, P: Pattern<'a>> { - /// The slice remaining to be iterated - start: usize, - end: usize, - matcher: P::Searcher, - /// Whether an empty string at the end is allowed - allow_trailing_empty: bool, - finished: bool, +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Bytes<'a> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } } -/// An iterator over the substrings of a string, separated by `sep`, -/// splitting at most `count` times. -struct CharSplitsN<'a, P: Pattern<'a>> { - iter: CharSplits<'a, P>, - /// The number of items remaining - count: usize, +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Bytes<'a> { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } } -/// An iterator over the substrings of a string, separated by a -/// pattern, in reverse order. -struct RCharSplits<'a, P: Pattern<'a>> { - /// The slice remaining to be iterated - start: usize, - end: usize, - matcher: P::Searcher, - /// Whether an empty string at the end of iteration is allowed - allow_final_empty: bool, - finished: bool, +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> ExactSizeIterator for Bytes<'a> { + #[inline] + fn len(&self) -> usize { + self.0.len() + } } -/// An iterator over the substrings of a string, separated by a -/// pattern, splitting at most `count` times, in reverse order. -struct RCharSplitsN<'a, P: Pattern<'a>> { - iter: RCharSplits<'a, P>, - /// The number of splits remaining - count: usize, +/// This macro generates a Clone impl for string pattern API +/// wrapper types of the form X<'a, P> +macro_rules! derive_pattern_clone { + (clone $t:ident with |$s:ident| $e:expr) => { + impl<'a, P: Pattern<'a>> Clone for $t<'a, P> + where P::Searcher: Clone + { + fn clone(&self) -> Self { + let $s = self; + $e + } + } + } } -/// An iterator over the lines of a string, separated by `\n`. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Lines<'a> { - inner: CharSplits<'a, char>, +/// This macro generates two public iterator structs +/// wrapping an private internal one that makes use of the `Pattern` API. +/// +/// For all patterns `P: Pattern<'a>` the following items will be +/// generated (generics ommitted): +/// +/// struct $forward_iterator($internal_iterator); +/// struct $reverse_iterator($internal_iterator); +/// +/// impl Iterator for $forward_iterator +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// impl DoubleEndedIterator for $forward_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl Iterator for $reverse_iterator +/// where P::Searcher: ReverseSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl DoubleEndedIterator for $reverse_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// The internal one is defined outside the macro, and has almost the same +/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and +/// `pattern::ReverseSearcher` for both forward and reverse iteration. +/// +/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given +/// `Pattern` might not return the same elements, so actually implementing +/// `DoubleEndedIterator` for it would be incorrect. +/// (See the docs in `str::pattern` for more details) +/// +/// However, the internal struct still represents a single ended iterator from +/// either end, and depending on pattern is also a valid double ended iterator, +/// so the two wrapper structs implement `Iterator` +/// and `DoubleEndedIterator` depending on the concrete pattern type, leading +/// to the complex impls seen above. +macro_rules! generate_pattern_iterators { + { + // Forward iterator + forward: + $(#[$forward_iterator_attribute:meta])* + struct $forward_iterator:ident; + + // Reverse iterator + reverse: + $(#[$reverse_iterator_attribute:meta])* + struct $reverse_iterator:ident; + + // Stability of all generated items + stability: + $(#[$common_stability_attribute:meta])* + + // Internal almost-iterator that is being delegated to + internal: + $internal_iterator:ident yielding ($iterty:ty); + + // Kind of delgation - either single ended or double ended + delegate $($t:tt)* + } => { + $(#[$forward_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $forward_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Clone for $forward_iterator<'a, P> + where P::Searcher: Clone + { + fn clone(&self) -> Self { + $forward_iterator(self.0.clone()) + } + } + + $(#[$reverse_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $reverse_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Iterator for $reverse_iterator<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Clone for $reverse_iterator<'a, P> + where P::Searcher: Clone + { + fn clone(&self) -> Self { + $reverse_iterator(self.0.clone()) + } + } + + generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, + $forward_iterator, + $reverse_iterator, $iterty); + }; + { + double ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => { + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> DoubleEndedIterator for $forward_iterator<'a, P> + where P::Searcher: DoubleEndedSearcher<'a> + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> DoubleEndedIterator for $reverse_iterator<'a, P> + where P::Searcher: DoubleEndedSearcher<'a> + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next() + } + } + }; + { + single ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => {} } -/// An iterator over the lines of a string, separated by either `\n` or (`\r\n`). -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LinesAny<'a> { - inner: Map, fn(&str) -> &str>, +derive_pattern_clone!{ + clone SplitInternal + with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } +} +struct SplitInternal<'a, P: Pattern<'a>> { + start: usize, + end: usize, + matcher: P::Searcher, + allow_trailing_empty: bool, + finished: bool, } -impl<'a, P: Pattern<'a>> CharSplits<'a, P> { +impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn get_end(&mut self) -> Option<&'a str> { if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { @@ -538,11 +588,6 @@ impl<'a, P: Pattern<'a>> CharSplits<'a, P> { None } } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> Iterator for CharSplits<'a, P> { - type Item = &'a str; #[inline] fn next(&mut self) -> Option<&'a str> { @@ -558,13 +603,11 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplits<'a, P> { None => self.get_end(), } } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> DoubleEndedIterator for CharSplits<'a, P> -where P::Searcher: DoubleEndedSearcher<'a> { #[inline] - fn next_back(&mut self) -> Option<&'a str> { + fn next_back(&mut self) -> Option<&'a str> + where P::Searcher: ReverseSearcher<'a> + { if self.finished { return None } if !self.allow_trailing_empty { @@ -590,10 +633,45 @@ where P::Searcher: DoubleEndedSearcher<'a> { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> { - type Item = &'a str; +generate_pattern_iterators! { + forward: + /// Created with the method `.split()`. + struct Split; + reverse: + /// Created with the method `.rsplit()`. + struct RSplit; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} + +generate_pattern_iterators! { + forward: + /// Created with the method `.split_terminator()`. + struct SplitTerminator; + reverse: + /// Created with the method `.rsplit_terminator()`. + struct RSplitTerminator; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} +derive_pattern_clone!{ + clone SplitNInternal + with |s| SplitNInternal { iter: s.iter.clone(), ..*s } +} +struct SplitNInternal<'a, P: Pattern<'a>> { + iter: SplitInternal<'a, P>, + /// The number of splits remaining + count: usize, +} + +impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { match self.count { @@ -602,58 +680,190 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> { _ => { self.count -= 1; self.iter.next() } } } -} -impl<'a, P: Pattern<'a>> RCharSplits<'a, P> { #[inline] - fn get_remainder(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_final_empty || self.end - self.start > 0) { - self.finished = true; - unsafe { - let string = self.matcher.haystack().slice_unchecked(self.start, self.end); - Some(string) - } - } else { - None + fn next_back(&mut self) -> Option<&'a str> + where P::Searcher: ReverseSearcher<'a> + { + match self.count { + 0 => None, + 1 => { self.count = 0; self.iter.get_end() } + _ => { self.count -= 1; self.iter.next_back() } } } } +generate_pattern_iterators! { + forward: + /// Created with the method `.splitn()`. + struct SplitN; + reverse: + /// Created with the method `.rsplitn()`. + struct RSplitN; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitNInternal yielding (&'a str); + delegate single ended; +} + +derive_pattern_clone!{ + clone MatchIndicesInternal + with |s| MatchIndicesInternal(s.0.clone()) +} +struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); + +impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<(usize, usize)> { + self.0.next_match() + } + + #[inline] + fn next_back(&mut self) -> Option<(usize, usize)> + where P::Searcher: ReverseSearcher<'a> + { + self.0.next_match_back() + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method `.match_indices()`. + struct MatchIndices; + reverse: + /// Created with the method `.rmatch_indices()`. + struct RMatchIndices; + stability: + #[unstable(feature = "core", + reason = "type may be removed or have its iterator impl changed")] + internal: + MatchIndicesInternal yielding ((usize, usize)); + delegate double ended; +} + +derive_pattern_clone!{ + clone MatchesInternal + with |s| MatchesInternal(s.0.clone()) +} +struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher); + +impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next_match().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().slice_unchecked(a, b) + }) + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where P::Searcher: ReverseSearcher<'a> + { + self.0.next_match_back().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().slice_unchecked(a, b) + }) + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method `.matches()`. + struct Matches; + reverse: + /// Created with the method `.rmatches()`. + struct RMatches; + stability: + #[unstable(feature = "core", reason = "type got recently added")] + internal: + MatchesInternal yielding (&'a str); + delegate double ended; +} + +/// Created with the method `.lines()`. #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> Iterator for RCharSplits<'a, P> - where P::Searcher: ReverseSearcher<'a> -{ +#[derive(Clone)] +pub struct Lines<'a>(SplitTerminator<'a, char>); + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Lines<'a> { type Item = &'a str; #[inline] fn next(&mut self) -> Option<&'a str> { - if self.finished { return None } + self.0.next() + } - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - Some((a, b)) => unsafe { - let elt = haystack.slice_unchecked(b, self.end); - self.end = a; - Some(elt) - }, - None => self.get_remainder(), - } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Lines<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() + } +} + +/// Created with the method `.lines_any()`. +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct LinesAny<'a>(Map, LinesAnyMap>); + +/// A nameable, clonable fn type +#[derive(Clone)] +struct LinesAnyMap; + +impl<'a> Fn<(&'a str,)> for LinesAnyMap { + #[inline] + extern "rust-call" fn call(&self, (line,): (&'a str,)) -> &'a str { + let l = line.len(); + if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } + else { line } + } +} + +impl<'a> FnMut<(&'a str,)> for LinesAnyMap { + #[inline] + extern "rust-call" fn call_mut(&mut self, (line,): (&'a str,)) -> &'a str { + Fn::call(&*self, (line,)) + } +} + +impl<'a> FnOnce<(&'a str,)> for LinesAnyMap { + type Output = &'a str; + + #[inline] + extern "rust-call" fn call_once(self, (line,): (&'a str,)) -> &'a str { + Fn::call(&self, (line,)) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P> - where P::Searcher: ReverseSearcher<'a> -{ +impl<'a> Iterator for LinesAny<'a> { type Item = &'a str; #[inline] fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { self.count -= 1; self.iter.get_remainder() } - _ => { self.count -= 1; self.iter.next() } - } + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for LinesAny<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() } } @@ -908,7 +1118,7 @@ enum OldSearcher { impl OldSearcher { #[allow(dead_code)] fn new(haystack: &[u8], needle: &[u8]) -> OldSearcher { - if needle.len() == 0 { + if needle.is_empty() { // Handle specially unimplemented!() // FIXME: Tune this. @@ -939,22 +1149,6 @@ struct OldMatchIndices<'a, 'b> { searcher: OldSearcher } -// FIXME: #21637 Prevents a Clone impl -/// An iterator over the start and end indices of the matches of a -/// substring within a larger string -#[unstable(feature = "core", reason = "type may be removed")] -pub struct MatchIndices<'a, P: Pattern<'a>>(P::Searcher); - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: Pattern<'a>> Iterator for MatchIndices<'a, P> { - type Item = (usize, usize); - - #[inline] - fn next(&mut self) -> Option<(usize, usize)> { - self.0.next_match() - } -} - impl<'a, 'b> OldMatchIndices<'a, 'b> { #[inline] #[allow(dead_code)] @@ -1016,14 +1210,16 @@ fn run_utf8_validation_iterator(iter: &mut slice::Iter) // restore the iterator we had at the start of this codepoint. macro_rules! err { () => {{ *iter = old.clone(); - return Err(Utf8Error::InvalidByte(whole.len() - iter.as_slice().len())) + return Err(Utf8Error { + valid_up_to: whole.len() - iter.as_slice().len() + }) }}} macro_rules! next { () => { match iter.next() { Some(a) => *a, // we needed data, but there was none: error! - None => return Err(Utf8Error::TooShort), + None => err!(), } }} @@ -1268,57 +1464,9 @@ mod traits { } } -/// Any string that can be represented as a slice -#[unstable(feature = "core", - reason = "Instead of taking this bound generically, this trait will be \ - replaced with one of slicing syntax (&foo[..]), deref coercions, or \ - a more generic conversion trait")] -#[deprecated(since = "1.0.0", - reason = "use std::convert::AsRef instead")] -pub trait Str { - /// Work with `self` as a slice. - fn as_slice<'a>(&'a self) -> &'a str; -} - -#[allow(deprecated)] -impl Str for str { - #[inline] - fn as_slice<'a>(&'a self) -> &'a str { self } -} - -#[allow(deprecated)] -impl<'a, S: ?Sized> Str for &'a S where S: Str { - #[inline] - fn as_slice(&self) -> &str { Str::as_slice(*self) } -} - -/// Return type of `str::split` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>); -delegate_iter!{pattern &'a str : Split<'a, P>} - -/// Return type of `str::split_terminator` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitTerminator<'a, P: Pattern<'a>>(CharSplits<'a, P>); -delegate_iter!{pattern &'a str : SplitTerminator<'a, P>} - -/// Return type of `str::splitn` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>); -delegate_iter!{pattern forward &'a str : SplitN<'a, P>} - -/// Return type of `str::rsplit` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplit<'a, P: Pattern<'a>>(RCharSplits<'a, P>); -delegate_iter!{pattern reverse &'a str : RSplit<'a, P>} - -/// Return type of `str::rsplitn` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitN<'a, P: Pattern<'a>>(RCharSplitsN<'a, P>); -delegate_iter!{pattern reverse &'a str : RSplitN<'a, P>} - /// Methods for string slices #[allow(missing_docs)] +#[doc(hidden)] pub trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // libcollections, not here. @@ -1329,13 +1477,20 @@ pub trait StrExt { fn bytes<'a>(&'a self) -> Bytes<'a>; fn char_indices<'a>(&'a self) -> CharIndices<'a>; fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>; - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>; - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>; fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> where P::Searcher: ReverseSearcher<'a>; + fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>; fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> where P::Searcher: ReverseSearcher<'a>; + fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>; + fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> + where P::Searcher: ReverseSearcher<'a>; + fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>; + fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> + where P::Searcher: ReverseSearcher<'a>; fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>; + fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a>; fn lines<'a>(&'a self) -> Lines<'a>; fn lines_any<'a>(&'a self) -> LinesAny<'a>; fn char_len(&self) -> usize; @@ -1402,7 +1557,7 @@ impl StrExt for str { #[inline] fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(CharSplits { + Split(SplitInternal { start: 0, end: self.len(), matcher: pat.into_searcher(self), @@ -1411,64 +1566,74 @@ impl StrExt for str { }) } + #[inline] + fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + RSplit(self.split(pat).0) + } + #[inline] fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { - SplitN(CharSplitsN { + SplitN(SplitNInternal { iter: self.split(pat).0, count: count, }) } + #[inline] + fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + RSplitN(self.splitn(count, pat).0) + } + #[inline] fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(CharSplits { + SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) } #[inline] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P::Searcher: ReverseSearcher<'a> { - RSplit(RCharSplits { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_final_empty: true, - finished: false, - }) + RSplitTerminator(self.split_terminator(pat).0) } #[inline] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> + fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + Matches(MatchesInternal(pat.into_searcher(self))) + } + + #[inline] + fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> where P::Searcher: ReverseSearcher<'a> { - RSplitN(RCharSplitsN { - iter: self.rsplit(pat).0, - count: count, - }) + RMatches(self.matches(pat).0) } #[inline] fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - MatchIndices(pat.into_searcher(self)) + MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } + #[inline] + fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + RMatchIndices(self.match_indices(pat).0) + } #[inline] fn lines(&self) -> Lines { - Lines { inner: self.split_terminator('\n').0 } + Lines(self.split_terminator('\n')) } + #[inline] fn lines_any(&self) -> LinesAny { - fn f(line: &str) -> &str { - let l = line.len(); - if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } - else { line } - } - - let f: fn(&str) -> &str = f; // coerce to fn pointer - LinesAny { inner: self.lines().map(f) } + LinesAny(self.lines().map(LinesAnyMap)) } #[inline] @@ -1709,35 +1874,3 @@ impl<'a> Default for &'a str { #[stable(feature = "rust1", since = "1.0.0")] fn default() -> &'a str { "" } } - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Lines<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { self.inner.next() } - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Lines<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for LinesAny<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { self.inner.next() } - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for LinesAny<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } -} diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 922ab2c14a..9a96612195 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! The string Pattern API. +//! +//! For more details, see the traits `Pattern`, `Searcher`, +//! `ReverseSearcher` and `DoubleEndedSearcher`. + use prelude::*; // Pattern @@ -27,17 +32,17 @@ pub trait Pattern<'a>: Sized { /// Associated searcher for this pattern type Searcher: Searcher<'a>; - /// Construct the associated searcher from + /// Constructs the associated searcher from /// `self` and the `haystack` to search in. fn into_searcher(self, haystack: &'a str) -> Self::Searcher; - /// Check whether the pattern matches anywhere in the haystack + /// Checks whether the pattern matches anywhere in the haystack #[inline] fn is_contained_in(self, haystack: &'a str) -> bool { self.into_searcher(haystack).next_match().is_some() } - /// Check whether the pattern matches at the front of the haystack + /// Checks whether the pattern matches at the front of the haystack #[inline] fn is_prefix_of(self, haystack: &'a str) -> bool { match self.into_searcher(haystack).next() { @@ -46,7 +51,7 @@ pub trait Pattern<'a>: Sized { } } - /// Check whether the pattern matches at the back of the haystack + /// Checks whether the pattern matches at the back of the haystack #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a> @@ -223,7 +228,9 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { /// `"[aa]a"` or `"a[aa]"`, depending from which side it is searched. pub trait DoubleEndedSearcher<'a>: ReverseSearcher<'a> {} +///////////////////////////////////////////////////////////////////////////// // Impl for a CharEq wrapper +///////////////////////////////////////////////////////////////////////////// #[doc(hidden)] trait CharEq { @@ -261,6 +268,7 @@ impl<'a> CharEq for &'a [char] { struct CharEqPattern(C); +#[derive(Clone)] struct CharEqSearcher<'a, C: CharEq> { char_eq: C, haystack: &'a str, @@ -330,17 +338,27 @@ 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)] -struct StrSearcher<'a, 'b> { +pub struct StrSearcher<'a, 'b> { haystack: &'a str, needle: &'b str, start: usize, end: usize, - done: bool, + 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. @@ -357,7 +375,7 @@ impl<'a, 'b> Pattern<'a> for &'b str { needle: self, start: 0, end: haystack.len(), - done: false, + state: State::NotDone, } } } @@ -374,8 +392,9 @@ unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { |m: &mut StrSearcher| { // Forward step for empty needle let current_start = m.start; - if !m.done { + 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) }, @@ -404,8 +423,9 @@ unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> { |m: &mut StrSearcher| { // Backward step for empty needle let current_end = m.end; - if !m.done { + 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) }, @@ -435,137 +455,178 @@ fn str_search_step(mut m: &mut StrSearcher, where F: FnOnce(&mut StrSearcher) -> SearchStep, G: FnOnce(&mut StrSearcher) -> SearchStep { - if m.done { + if m.state.done() { SearchStep::Done - } else if m.needle.len() == 0 && m.start <= m.end { + } else if m.needle.is_empty() && m.start <= m.end { // Case for needle == "" - if m.start == m.end { - m.done = true; + 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) } - 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.done = true; + m.state = State::Done; SearchStep::Reject(m.start, m.end) } else { - m.done = true; + m.state = State::Done; SearchStep::Done } } -macro_rules! char_eq_pattern_impl { - ($wrapper:ty, $wrapper_ident:ident) => { - fn into_searcher(self, haystack: &'a str) -> $wrapper { - $wrapper_ident(CharEqPattern(self).into_searcher(haystack)) +///////////////////////////////////////////////////////////////////////////// + +macro_rules! pattern_methods { + ($t:ty, $pmap:expr, $smap:expr) => { + type Searcher = $t; + + #[inline] + fn into_searcher(self, haystack: &'a str) -> $t { + ($smap)(($pmap)(self).into_searcher(haystack)) } + #[inline] fn is_contained_in(self, haystack: &'a str) -> bool { - CharEqPattern(self).is_contained_in(haystack) + ($pmap)(self).is_contained_in(haystack) } + #[inline] fn is_prefix_of(self, haystack: &'a str) -> bool { - CharEqPattern(self).is_prefix_of(haystack) + ($pmap)(self).is_prefix_of(haystack) } + #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool - where $wrapper: ReverseSearcher<'a> + where $t: ReverseSearcher<'a> { - CharEqPattern(self).is_suffix_of(haystack) + ($pmap)(self).is_suffix_of(haystack) } } } -// Pattern for char - -impl<'a> Pattern<'a> for char { - type Searcher = CharSearcher<'a>; - char_eq_pattern_impl!(CharSearcher<'a>, CharSearcher); +macro_rules! searcher_methods { + (forward) => { + #[inline] + fn haystack(&self) -> &'a str { + self.0.haystack() + } + #[inline] + fn next(&mut self) -> SearchStep { + self.0.next() + } + #[inline] + fn next_match(&mut self) -> Option<(usize, usize)> { + self.0.next_match() + } + #[inline] + fn next_reject(&mut self) -> Option<(usize, usize)> { + self.0.next_reject() + } + }; + (reverse) => { + #[inline] + fn next_back(&mut self) -> SearchStep { + self.0.next_back() + } + #[inline] + fn next_match_back(&mut self) -> Option<(usize, usize)> { + self.0.next_match_back() + } + #[inline] + fn next_reject_back(&mut self) -> Option<(usize, usize)> { + self.0.next_reject_back() + } + } } -pub struct CharSearcher<'a>(CharEqSearcher<'a, char>); +///////////////////////////////////////////////////////////////////////////// +// Impl for char +///////////////////////////////////////////////////////////////////////////// + +/// Associated type for `>::Searcher`. +#[derive(Clone)] +pub struct CharSearcher<'a>( as Pattern<'a>>::Searcher); unsafe impl<'a> Searcher<'a> for CharSearcher<'a> { - #[inline] - fn haystack(&self) -> &'a str { self.0.haystack() } - #[inline] - fn next(&mut self) -> SearchStep { self.0.next() } + searcher_methods!(forward); } + unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { - #[inline] - fn next_back(&mut self) -> SearchStep { self.0.next_back() } + searcher_methods!(reverse); } -impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} -// Pattern for &[char] +impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {} -impl<'a, 'b> Pattern<'a> for &'b [char] { - type Searcher = CharSliceSearcher<'a, 'b>; - char_eq_pattern_impl!(CharSliceSearcher<'a, 'b>, CharSliceSearcher); +/// Searches for chars that are equal to a given char +impl<'a> Pattern<'a> for char { + pattern_methods!(CharSearcher<'a>, CharEqPattern, CharSearcher); } -pub struct CharSliceSearcher<'a, 'b>(CharEqSearcher<'a, &'b [char]>); +///////////////////////////////////////////////////////////////////////////// +// Impl for &[char] +///////////////////////////////////////////////////////////////////////////// + +// Todo: Change / Remove due to ambiguity in meaning. + +/// Associated type for `<&[char] as Pattern<'a>>::Searcher`. +#[derive(Clone)] +pub struct CharSliceSearcher<'a, 'b>( as Pattern<'a>>::Searcher); unsafe impl<'a, 'b> Searcher<'a> for CharSliceSearcher<'a, 'b> { - #[inline] - fn haystack(&self) -> &'a str { self.0.haystack() } - #[inline] - fn next(&mut self) -> SearchStep { self.0.next() } + searcher_methods!(forward); } + unsafe impl<'a, 'b> ReverseSearcher<'a> for CharSliceSearcher<'a, 'b> { - #[inline] - fn next_back(&mut self) -> SearchStep { self.0.next_back() } + searcher_methods!(reverse); } -impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} -// Pattern for predicates +impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} -impl<'a, F: FnMut(char) -> bool> Pattern<'a> for F { - type Searcher = CharPredSearcher<'a, F>; - char_eq_pattern_impl!(CharPredSearcher<'a, F>, CharPredSearcher); +/// Searches for chars that are equal to any of the chars in the array +impl<'a, 'b> Pattern<'a> for &'b [char] { + pattern_methods!(CharSliceSearcher<'a, 'b>, CharEqPattern, CharSliceSearcher); } -pub struct CharPredSearcher<'a, F: FnMut(char) -> bool>(CharEqSearcher<'a, F>); +///////////////////////////////////////////////////////////////////////////// +// Impl for F: FnMut(char) -> bool +///////////////////////////////////////////////////////////////////////////// + +/// Associated type for `>::Searcher`. +#[derive(Clone)] +pub struct CharPredicateSearcher<'a, F>( as Pattern<'a>>::Searcher) + where F: FnMut(char) -> bool; -unsafe impl<'a, F> Searcher<'a> for CharPredSearcher<'a, F> +unsafe impl<'a, F> Searcher<'a> for CharPredicateSearcher<'a, F> where F: FnMut(char) -> bool { - #[inline] - fn haystack(&self) -> &'a str { self.0.haystack() } - #[inline] - fn next(&mut self) -> SearchStep { self.0.next() } + searcher_methods!(forward); } -unsafe impl<'a, F> ReverseSearcher<'a> for CharPredSearcher<'a, F> + +unsafe impl<'a, F> ReverseSearcher<'a> for CharPredicateSearcher<'a, F> where F: FnMut(char) -> bool { - #[inline] - fn next_back(&mut self) -> SearchStep { self.0.next_back() } + searcher_methods!(reverse); } -impl<'a, F> DoubleEndedSearcher<'a> for CharPredSearcher<'a, F> - where F: FnMut(char) -> bool -{} -// Pattern for &&str +impl<'a, F> DoubleEndedSearcher<'a> for CharPredicateSearcher<'a, F> + where F: FnMut(char) -> bool {} +/// Searches for chars that match the given predicate +impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool { + pattern_methods!(CharPredicateSearcher<'a, F>, CharEqPattern, CharPredicateSearcher); +} + +///////////////////////////////////////////////////////////////////////////// +// Impl for &&str +///////////////////////////////////////////////////////////////////////////// + +/// Delegates to the `&str` impl. impl<'a, 'b> Pattern<'a> for &'b &'b str { - type Searcher = <&'b str as Pattern<'a>>::Searcher; - #[inline] - fn into_searcher(self, haystack: &'a str) - -> <&'b str as Pattern<'a>>::Searcher { - (*self).into_searcher(haystack) - } - #[inline] - fn is_contained_in(self, haystack: &'a str) -> bool { - (*self).is_contained_in(haystack) - } - #[inline] - fn is_prefix_of(self, haystack: &'a str) -> bool { - (*self).is_prefix_of(haystack) - } - #[inline] - fn is_suffix_of(self, haystack: &'a str) -> bool { - (*self).is_suffix_of(haystack) - } + pattern_methods!(StrSearcher<'a, 'b>, |&s| s, |s| s); } diff --git a/src/libcoretest/cmp.rs b/src/libcoretest/cmp.rs index 9ed1508c3e..e0d396c68b 100644 --- a/src/libcoretest/cmp.rs +++ b/src/libcoretest/cmp.rs @@ -110,8 +110,6 @@ fn test_partial_max() { #[test] fn test_user_defined_eq() { - use core::num::SignedInt; - // Our type. struct SketchyNum { num : isize diff --git a/src/libcoretest/fmt/float.rs b/src/libcoretest/fmt/float.rs new file mode 100644 index 0000000000..6b14fa8be8 --- /dev/null +++ b/src/libcoretest/fmt/float.rs @@ -0,0 +1,17 @@ +// Copyright 2014 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. + +#[test] +fn test_format_float() { + assert!("1" == format!("{:.0}", 1.0f64)); + assert!("9" == format!("{:.0}", 9.4f64)); + assert!("10" == format!("{:.0}", 9.9f64)); + assert!("9.9" == format!("{:.1}", 9.85f64)); +} diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index ba12ff306e..cab2175f89 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -169,42 +169,42 @@ fn test_radix_base_too_large() { mod u32 { use test::Bencher; use core::fmt::radix; - use std::rand::{weak_rng, Rng}; + use std::__rand::{thread_rng, Rng}; use std::io::{Write, sink}; #[bench] fn format_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:b}", rng.gen::()) }) } #[bench] fn format_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:o}", rng.gen::()) }) } #[bench] fn format_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", rng.gen::()) }) } #[bench] fn format_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:x}", rng.gen::()) }) } #[bench] fn format_show(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:?}", rng.gen::()) }) } #[bench] fn format_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", radix(rng.gen::(), 36)) }) } } @@ -212,42 +212,42 @@ mod u32 { mod i32 { use test::Bencher; use core::fmt::radix; - use std::rand::{weak_rng, Rng}; + use std::__rand::{thread_rng, Rng}; use std::io::{Write, sink}; #[bench] fn format_bin(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:b}", rng.gen::()) }) } #[bench] fn format_oct(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:o}", rng.gen::()) }) } #[bench] fn format_dec(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", rng.gen::()) }) } #[bench] fn format_hex(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:x}", rng.gen::()) }) } #[bench] fn format_show(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{:?}", rng.gen::()) }) } #[bench] fn format_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); + let mut rng = thread_rng(); b.iter(|| { write!(&mut sink(), "{}", radix(rng.gen::(), 36)) }) } } diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index af80d347f0..2866c193c3 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -11,7 +11,6 @@ use core::iter::*; use core::iter::order::*; use core::iter::MinMaxResult::*; -use core::num::SignedInt; use core::usize; use core::cmp; @@ -329,17 +328,17 @@ fn test_iterator_len() { #[test] fn test_iterator_sum() { let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().sum(), 6); - assert_eq!(v.iter().cloned().sum(), 55); - assert_eq!(v[..0].iter().cloned().sum(), 0); + assert_eq!(v[..4].iter().cloned().sum::(), 6); + assert_eq!(v.iter().cloned().sum::(), 55); + assert_eq!(v[..0].iter().cloned().sum::(), 0); } #[test] fn test_iterator_product() { let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..4].iter().cloned().product(), 0); - assert_eq!(v[1..5].iter().cloned().product(), 24); - assert_eq!(v[..0].iter().cloned().product(), 1); + assert_eq!(v[..4].iter().cloned().product::(), 0); + assert_eq!(v[1..5].iter().cloned().product::(), 24); + assert_eq!(v[..0].iter().cloned().product::(), 1); } #[test] @@ -783,16 +782,6 @@ fn test_range_step() { assert_eq!((200..200).step_by(1).collect::>(), []); } -#[test] -fn test_range_step_inclusive() { - assert_eq!(range_step_inclusive(0, 20, 5).collect::>(), [0, 5, 10, 15, 20]); - assert_eq!(range_step_inclusive(20, 0, -5).collect::>(), [20, 15, 10, 5, 0]); - assert_eq!(range_step_inclusive(20, 0, -6).collect::>(), [20, 14, 8, 2]); - assert_eq!(range_step_inclusive(200, 255, 50).collect::>(), [200, 250]); - assert_eq!(range_step_inclusive(200, -5, 1).collect::>(), []); - assert_eq!(range_step_inclusive(200, 200, 1).collect::>(), [200]); -} - #[test] fn test_reverse() { let mut ys = [1, 2, 3, 4, 5]; @@ -901,3 +890,34 @@ fn bench_multiple_take(b: &mut Bencher) { } }); } + +fn scatter(x: i32) -> i32 { (x * 31) % 127 } + +#[bench] +fn bench_max_by(b: &mut Bencher) { + b.iter(|| { + let it = 0..100; + it.max_by(|&x| scatter(x)) + }) +} + +// http://www.reddit.com/r/rust/comments/31syce/using_iterators_to_find_the_index_of_the_min_or/ +#[bench] +fn bench_max_by2(b: &mut Bencher) { + fn max_index_iter(array: &[i32]) -> usize { + array.iter().enumerate().max_by(|&(_, item)| item).unwrap().0 + } + + let mut data = vec![0i32; 1638]; + data[514] = 9999; + + b.iter(|| max_index_iter(&data)); +} + +#[bench] +fn bench_max(b: &mut Bencher) { + b.iter(|| { + let it = 0..100; + it.map(scatter).max() + }) +} diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 7ae0dcbb5f..7a66fa0f10 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -10,8 +10,8 @@ // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) #![cfg_attr(stage0, feature(custom_attribute))] + #![feature(box_syntax)] -#![feature(int_uint)] #![feature(unboxed_closures)] #![feature(unsafe_destructor)] #![feature(core)] @@ -21,13 +21,11 @@ #![feature(std_misc)] #![feature(libc)] #![feature(hash)] -#![feature(io)] -#![feature(collections)] #![feature(debug_builders)] #![feature(unique)] #![feature(step_by)] #![feature(slice_patterns)] -#![allow(deprecated)] // rand +#![feature(float_from_str_radix)] extern crate core; extern crate test; diff --git a/src/libcoretest/num/int_macros.rs b/src/libcoretest/num/int_macros.rs index fa41167cae..b1c8aec3c3 100644 --- a/src/libcoretest/num/int_macros.rs +++ b/src/libcoretest/num/int_macros.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -macro_rules! int_module { ($T:ty, $T_i:ident) => ( +macro_rules! int_module { ($T:ident, $T_i:ident) => ( #[cfg(test)] mod tests { use core::$T_i::*; use core::isize; - use core::num::{FromStrRadix, Int, SignedInt}; use core::ops::{Shl, Shr, Not, BitXor, BitAnd, BitOr}; use num; @@ -86,9 +85,9 @@ mod tests { #[test] fn test_count_zeros() { - assert!(A.count_zeros() == BITS - 3); - assert!(B.count_zeros() == BITS - 2); - assert!(C.count_zeros() == BITS - 5); + assert!(A.count_zeros() == BITS as u32 - 3); + assert!(B.count_zeros() == BITS as u32 - 2); + assert!(C.count_zeros() == BITS as u32 - 5); } #[test] @@ -129,30 +128,30 @@ mod tests { #[test] fn test_le() { - assert_eq!(Int::from_le(A.to_le()), A); - assert_eq!(Int::from_le(B.to_le()), B); - assert_eq!(Int::from_le(C.to_le()), C); - assert_eq!(Int::from_le(_0), _0); - assert_eq!(Int::from_le(_1), _1); + assert_eq!($T::from_le(A.to_le()), A); + assert_eq!($T::from_le(B.to_le()), B); + assert_eq!($T::from_le(C.to_le()), C); + assert_eq!($T::from_le(_0), _0); + assert_eq!($T::from_le(_1), _1); assert_eq!(_0.to_le(), _0); assert_eq!(_1.to_le(), _1); } #[test] fn test_be() { - assert_eq!(Int::from_be(A.to_be()), A); - assert_eq!(Int::from_be(B.to_be()), B); - assert_eq!(Int::from_be(C.to_be()), C); - assert_eq!(Int::from_be(_0), _0); - assert_eq!(Int::from_be(_1), _1); + assert_eq!($T::from_be(A.to_be()), A); + assert_eq!($T::from_be(B.to_be()), B); + assert_eq!($T::from_be(C.to_be()), C); + assert_eq!($T::from_be(_0), _0); + assert_eq!($T::from_be(_1), _1); assert_eq!(_0.to_be(), _0); assert_eq!(_1.to_be(), _1); } #[test] fn test_signed_checked_div() { - assert!(10.checked_div(2) == Some(5)); - assert!(5.checked_div(0) == None); + assert!((10 as $T).checked_div(2) == Some(5)); + assert!((5 as $T).checked_div(0) == None); assert!(isize::MIN.checked_div(-1) == None); } @@ -180,26 +179,26 @@ mod tests { #[test] fn test_from_str_radix() { - assert_eq!(FromStrRadix::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 16), Ok(291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Ok(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Ok(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("z", 36), Ok(35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("Z", 36), Ok(35 as $T)); - - assert_eq!(FromStrRadix::from_str_radix("-123", 10), Ok(-123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Ok(-9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 8), Ok(-83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 16), Ok(-291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Ok(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-z", 36), Ok(-35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Ok(-35 as $T)); - - assert_eq!(FromStrRadix::from_str_radix("Z", 35).ok(), None::<$T>); - assert_eq!(FromStrRadix::from_str_radix("-9", 2).ok(), None::<$T>); + assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq!(i32::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq!(i32::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq!(i32::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq!($T::from_str_radix("Z", 36), Ok(35 as $T)); + + assert_eq!($T::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq!($T::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq!($T::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq!(i32::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq!(i32::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq!(i32::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq!($T::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq!($T::from_str_radix("-Z", 36), Ok(-35 as $T)); + + assert_eq!($T::from_str_radix("Z", 35).ok(), None::<$T>); + assert_eq!($T::from_str_radix("-9", 2).ok(), None::<$T>); } #[test] diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 9087b87f64..85ca547da8 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -10,7 +10,6 @@ use core::cmp::PartialEq; use core::fmt::Debug; -use core::num::{NumCast, cast}; use core::ops::{Add, Sub, Mul, Div, Rem}; use core::marker::Copy; @@ -32,18 +31,12 @@ mod u64; /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where - T: PartialEq + NumCast + T: PartialEq + Add + Sub + Mul + Div + Rem + Debug + Copy { - assert_eq!(ten.add(two), cast(12).unwrap()); - assert_eq!(ten.sub(two), cast(8).unwrap()); - assert_eq!(ten.mul(two), cast(20).unwrap()); - assert_eq!(ten.div(two), cast(5).unwrap()); - assert_eq!(ten.rem(two), cast(0).unwrap()); - assert_eq!(ten.add(two), ten + two); assert_eq!(ten.sub(two), ten - two); assert_eq!(ten.mul(two), ten * two); @@ -56,33 +49,33 @@ mod test { use core::option::Option; use core::option::Option::{Some, None}; use core::num::Float; - use core::num::from_str_radix; #[test] fn from_str_issue7588() { - let u : Option = from_str_radix("1000", 10).ok(); + let u : Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); - let s : Option = from_str_radix("80000", 10).ok(); + let s : Option = i16::from_str_radix("80000", 10).ok(); assert_eq!(s, None); - let f : Option = from_str_radix("10000000000000000000000000000000000000000", 10).ok(); + let s = "10000000000000000000000000000000000000000"; + let f : Option = f32::from_str_radix(s, 10).ok(); assert_eq!(f, Some(Float::infinity())); - let fe : Option = from_str_radix("1e40", 10).ok(); + let fe : Option = f32::from_str_radix("1e40", 10).ok(); assert_eq!(fe, Some(Float::infinity())); } #[test] fn test_from_str_radix_float() { - let x1 : Option = from_str_radix("-123.456", 10).ok(); + let x1 : Option = f64::from_str_radix("-123.456", 10).ok(); assert_eq!(x1, Some(-123.456)); - let x2 : Option = from_str_radix("123.456", 10).ok(); + let x2 : Option = f32::from_str_radix("123.456", 10).ok(); assert_eq!(x2, Some(123.456)); - let x3 : Option = from_str_radix("-0.0", 10).ok(); + let x3 : Option = f32::from_str_radix("-0.0", 10).ok(); assert_eq!(x3, Some(-0.0)); - let x4 : Option = from_str_radix("0.0", 10).ok(); + let x4 : Option = f32::from_str_radix("0.0", 10).ok(); assert_eq!(x4, Some(0.0)); - let x4 : Option = from_str_radix("1.0", 10).ok(); + let x4 : Option = f32::from_str_radix("1.0", 10).ok(); assert_eq!(x4, Some(1.0)); - let x5 : Option = from_str_radix("-1.0", 10).ok(); + let x5 : Option = f32::from_str_radix("-1.0", 10).ok(); assert_eq!(x5, Some(-1.0)); } diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcoretest/num/uint_macros.rs index e3eff6e751..1712345f9d 100644 --- a/src/libcoretest/num/uint_macros.rs +++ b/src/libcoretest/num/uint_macros.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -macro_rules! uint_module { ($T:ty, $T_i:ident) => ( +macro_rules! uint_module { ($T:ident, $T_i:ident) => ( #[cfg(test)] mod tests { use core::$T_i::*; - use core::num::Int; use num; use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not}; @@ -54,9 +53,9 @@ mod tests { #[test] fn test_count_zeros() { - assert!(A.count_zeros() == BITS - 3); - assert!(B.count_zeros() == BITS - 2); - assert!(C.count_zeros() == BITS - 5); + assert!(A.count_zeros() == BITS as u32 - 3); + assert!(B.count_zeros() == BITS as u32 - 2); + assert!(C.count_zeros() == BITS as u32 - 5); } #[test] @@ -97,30 +96,30 @@ mod tests { #[test] fn test_le() { - assert_eq!(Int::from_le(A.to_le()), A); - assert_eq!(Int::from_le(B.to_le()), B); - assert_eq!(Int::from_le(C.to_le()), C); - assert_eq!(Int::from_le(_0), _0); - assert_eq!(Int::from_le(_1), _1); + assert_eq!($T::from_le(A.to_le()), A); + assert_eq!($T::from_le(B.to_le()), B); + assert_eq!($T::from_le(C.to_le()), C); + assert_eq!($T::from_le(_0), _0); + assert_eq!($T::from_le(_1), _1); assert_eq!(_0.to_le(), _0); assert_eq!(_1.to_le(), _1); } #[test] fn test_be() { - assert_eq!(Int::from_be(A.to_be()), A); - assert_eq!(Int::from_be(B.to_be()), B); - assert_eq!(Int::from_be(C.to_be()), C); - assert_eq!(Int::from_be(_0), _0); - assert_eq!(Int::from_be(_1), _1); + assert_eq!($T::from_be(A.to_be()), A); + assert_eq!($T::from_be(B.to_be()), B); + assert_eq!($T::from_be(C.to_be()), C); + assert_eq!($T::from_be(_0), _0); + assert_eq!($T::from_be(_1), _1); assert_eq!(_0.to_be(), _0); assert_eq!(_1.to_be(), _1); } #[test] fn test_unsigned_checked_div() { - assert!(10.checked_div(2) == Some(5)); - assert!(5.checked_div(0) == None); + assert!((10 as $T).checked_div(2) == Some(5)); + assert!((5 as $T).checked_div(0) == None); } } diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index 5fce527d97..b7d9ba4463 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -8,378 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[test] -fn test_pattern_deref_forward() { - let data = "aabcdaa"; - assert!(data.contains("bcd")); - assert!(data.contains(&"bcd")); - assert!(data.contains(&"bcd".to_string())); -} - -#[test] -fn test_empty_match_indices() { - let data = "aä中!"; - let vec: Vec<_> = data.match_indices("").collect(); - assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]); -} - -#[test] -fn test_bool_from_str() { - assert_eq!("true".parse().ok(), Some(true)); - assert_eq!("false".parse().ok(), Some(false)); - assert_eq!("not even a boolean".parse::().ok(), None); -} - -fn check_contains_all_substrings(s: &str) { - assert!(s.contains("")); - for i in 0..s.len() { - for j in i+1..s.len() + 1 { - assert!(s.contains(&s[i..j])); - } - } -} - -#[test] -fn strslice_issue_16589() { - assert!("bananas".contains("nana")); - - // prior to the fix for #16589, x.contains("abcdabcd") returned false - // test all substrings for good measure - check_contains_all_substrings("012345678901234567890123456789bcdabcdabcd"); -} - -#[test] -fn strslice_issue_16878() { - assert!(!"1234567ah012345678901ah".contains("hah")); - assert!(!"00abc01234567890123456789abc".contains("bcabc")); -} - - -#[test] -fn test_strslice_contains() { - let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; - check_contains_all_substrings(x); -} - -#[test] -fn test_rsplitn_char_iterator() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); - - // Unicode - let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); - - let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); - split.reverse(); - assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); -} - -#[test] -fn test_split_char_iterator() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let split: Vec<&str> = data.split(' ').collect(); - assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut rsplit: Vec<&str> = data.split(' ').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let split: Vec<&str> = data.split(|c: char| c == ' ').collect(); - assert_eq!( split, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - let mut rsplit: Vec<&str> = data.split(|c: char| c == ' ').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nMäry", "häd", "ä", "little", "lämb\nLittle", "lämb\n"]); - - // Unicode - let split: Vec<&str> = data.split('ä').collect(); - assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let mut rsplit: Vec<&str> = data.split('ä').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let split: Vec<&str> = data.split(|c: char| c == 'ä').collect(); - assert_eq!( split, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); - - let mut rsplit: Vec<&str> = data.split(|c: char| c == 'ä').rev().collect(); - rsplit.reverse(); - assert_eq!(rsplit, ["\nM", "ry h", "d ", " little l", "mb\nLittle l", "mb\n"]); -} - -#[test] -fn test_rev_split_char_iterator_no_trailing() { - let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - - let mut split: Vec<&str> = data.split('\n').rev().collect(); - split.reverse(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb", ""]); - - let mut split: Vec<&str> = data.split_terminator('\n').rev().collect(); - split.reverse(); - assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]); -} - -#[test] -fn test_utf16_code_units() { - use unicode::str::Utf16Encoder; - assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::>(), - [0xE9, 0xD83D, 0xDCA9]) -} - -#[test] -fn starts_with_in_unicode() { - assert!(!"├── Cargo.toml".starts_with("# ")); -} - -#[test] -fn starts_short_long() { - assert!(!"".starts_with("##")); - assert!(!"##".starts_with("####")); - assert!("####".starts_with("##")); - assert!(!"##ä".starts_with("####")); - assert!("####ä".starts_with("##")); - assert!(!"##".starts_with("####ä")); - assert!("##ä##".starts_with("##ä")); - - assert!("".starts_with("")); - assert!("ä".starts_with("")); - assert!("#ä".starts_with("")); - assert!("##ä".starts_with("")); - assert!("ä###".starts_with("")); - assert!("#ä##".starts_with("")); - assert!("##ä#".starts_with("")); -} - -#[test] -fn contains_weird_cases() { - assert!("* \t".contains(' ')); - assert!(!"* \t".contains('?')); - assert!(!"* \t".contains('\u{1F4A9}')); -} - -#[test] -fn trim_ws() { - assert_eq!(" \t a \t ".trim_left_matches(|c: char| c.is_whitespace()), - "a \t "); - assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()), - " \t a"); - assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()), - "a"); - assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()), - ""); - assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()), - ""); - assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()), - ""); -} - -mod pattern { - use std::str::Pattern; - use std::str::{Searcher, ReverseSearcher}; - use std::str::SearchStep::{self, Match, Reject, Done}; - - macro_rules! make_test { - ($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => { - mod $name { - use std::str::SearchStep::{Match, Reject}; - use super::{cmp_search_to_vec}; - #[test] - fn fwd() { - cmp_search_to_vec(false, $p, $h, vec![$($e),*]); - } - #[test] - fn bwd() { - cmp_search_to_vec(true, $p, $h, vec![$($e),*]); - } - } - } - } - - fn cmp_search_to_vec<'a, P: Pattern<'a>>(rev: bool, pat: P, haystack: &'a str, - right: Vec) - where P::Searcher: ReverseSearcher<'a> - { - let mut searcher = pat.into_searcher(haystack); - let mut v = vec![]; - loop { - match if !rev {searcher.next()} else {searcher.next_back()} { - Match(a, b) => v.push(Match(a, b)), - Reject(a, b) => v.push(Reject(a, b)), - Done => break, - } - } - if rev { - v.reverse(); - } - assert_eq!(v, right); - } - - make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [ - Reject(0, 1), - Match (1, 3), - Reject(3, 4), - Match (4, 6), - Reject(6, 7), - ]); - make_test!(str_searcher_empty_needle_ascii_haystack, "", "abbcbbd", [ - Match(0, 0), - Match(1, 1), - Match(2, 2), - Match(3, 3), - Match(4, 4), - Match(5, 5), - Match(6, 6), - Match(7, 7), - ]); - make_test!(str_searcher_mulibyte_haystack, " ", "├──", [ - Reject(0, 3), - Reject(3, 6), - Reject(6, 9), - ]); - make_test!(str_searcher_empty_needle_mulibyte_haystack, "", "├──", [ - Match(0, 0), - Match(3, 3), - Match(6, 6), - Match(9, 9), - ]); - make_test!(str_searcher_empty_needle_empty_haystack, "", "", [ - Match(0, 0), - ]); - make_test!(str_searcher_nonempty_needle_empty_haystack, "├", "", [ - ]); - make_test!(char_searcher_ascii_haystack, 'b', "abbcbbd", [ - Reject(0, 1), - Match (1, 2), - Match (2, 3), - Reject(3, 4), - Match (4, 5), - Match (5, 6), - Reject(6, 7), - ]); - make_test!(char_searcher_mulibyte_haystack, ' ', "├──", [ - Reject(0, 3), - Reject(3, 6), - Reject(6, 9), - ]); - make_test!(char_searcher_short_haystack, '\u{1F4A9}', "* \t", [ - Reject(0, 1), - Reject(1, 2), - Reject(2, 3), - ]); - -} - -mod bench { - macro_rules! make_test_inner { - ($s:ident, $code:expr, $name:ident, $str:expr) => { - #[bench] - fn $name(bencher: &mut Bencher) { - let mut $s = $str; - black_box(&mut $s); - bencher.iter(|| $code); - } - } - } - - macro_rules! make_test { - ($name:ident, $s:ident, $code:expr) => { - mod $name { - use test::Bencher; - use test::black_box; - - // Short strings: 65 bytes each - make_test_inner!($s, $code, short_ascii, - "Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!"); - make_test_inner!($s, $code, short_mixed, - "ศไทย中华Việt Nam; Mary had a little lamb, Little lam!"); - make_test_inner!($s, $code, short_pile_of_poo, - "💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!"); - make_test_inner!($s, $code, long_lorem_ipsum,"\ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ -ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ -eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ -sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ -tempus vel, gravida nec quam. - -In est dui, tincidunt sed tempus interdum, adipiscing laoreet ante. Etiam tempor, tellus quis \ -sagittis interdum, nulla purus mattis sem, quis auctor erat odio ac tellus. In nec nunc sit amet \ -diam volutpat molestie at sed ipsum. Vestibulum laoreet consequat vulputate. Integer accumsan \ -lorem ac dignissim placerat. Suspendisse convallis faucibus lorem. Aliquam erat volutpat. In vel \ -eleifend felis. Sed suscipit nulla lorem, sed mollis est sollicitudin et. Nam fermentum egestas \ -interdum. Curabitur ut nisi justo. - -Sed sollicitudin ipsum tellus, ut condimentum leo eleifend nec. Cras ut velit ante. Phasellus nec \ -mollis odio. Mauris molestie erat in arcu mattis, at aliquet dolor vehicula. Quisque malesuada \ -lectus sit amet nisi pretium, a condimentum ipsum porta. Morbi at dapibus diam. Praesent egestas \ -est sed risus elementum, eu rutrum metus ultrices. Etiam fermentum consectetur magna, id rutrum \ -felis accumsan a. Aliquam ut pellentesque libero. Sed mi nulla, lobortis eu tortor id, suscipit \ -ultricies neque. Morbi iaculis sit amet risus at iaculis. Praesent eget ligula quis turpis \ -feugiat suscipit vel non arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. \ -Aliquam sit amet placerat lorem. - -Cras a lacus vel ante posuere elementum. Nunc est leo, bibendum ut facilisis vel, bibendum at \ -mauris. Nullam adipiscing diam vel odio ornare, luctus adipiscing mi luctus. Nulla facilisi. \ -Mauris adipiscing bibendum neque, quis adipiscing lectus tempus et. Sed feugiat erat et nisl \ -lobortis pharetra. Donec vitae erat enim. Nullam sit amet felis et quam lacinia tincidunt. Aliquam \ -suscipit dapibus urna. Sed volutpat urna in magna pulvinar volutpat. Phasellus nec tellus ac diam \ -cursus accumsan. - -Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas eleifend dictum \ -feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \ -vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \ -leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \ -malesuada sollicitudin quam eu fermentum!"); - } - } - } - - make_test!(chars_count, s, s.chars().count()); - - make_test!(contains_bang_str, s, s.contains("!")); - make_test!(contains_bang_char, s, s.contains('!')); - - make_test!(match_indices_a_str, s, s.match_indices("a").count()); - - make_test!(split_a_str, s, s.split("a").count()); - - make_test!(trim_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_matches(|c: char| c.is_ascii()) - }); - make_test!(trim_left_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_left_matches(|c: char| c.is_ascii()) - }); - make_test!(trim_right_ascii_char, s, { - use std::ascii::AsciiExt; - s.trim_right_matches(|c: char| c.is_ascii()) - }); - - make_test!(find_underscore_char, s, s.find('_')); - make_test!(rfind_underscore_char, s, s.rfind('_')); - make_test!(find_underscore_str, s, s.find("_")); - - make_test!(find_zzz_char, s, s.find('\u{1F4A4}')); - make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}')); - make_test!(find_zzz_str, s, s.find("\u{1F4A4}")); - - make_test!(split_space_char, s, s.split(' ').count()); - make_test!(split_terminator_space_char, s, s.split_terminator(' ').count()); - - make_test!(splitn_space_char, s, s.splitn(10, ' ').count()); - make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); - - make_test!(split_space_str, s, s.split(" ").count()); - make_test!(split_ad_str, s, s.split("ad").count()); -} +// All `str` tests live in libcollectiontest::str diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index 63d1fe968f..1e0e201805 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -155,12 +155,11 @@ pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result { mod tests { #![allow(deprecated)] use super::{inflate_bytes, deflate_bytes}; - use std::rand; - use std::rand::Rng; + use std::__rand::{thread_rng, Rng}; #[test] fn test_flate_round_trip() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut words = vec![]; for _ in 0..20 { let range = r.gen_range(1, 10); diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 4cf93ab264..fa2ae79688 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -371,7 +371,7 @@ impl<'a> Parser<'a> { None => { let tmp = self.cur.clone(); match self.word() { - word if word.len() > 0 => { + word if !word.is_empty() => { if self.consume('$') { CountIsName(word) } else { @@ -463,7 +463,7 @@ mod tests { fn musterr(s: &str) { let mut p = Parser::new(s); p.next(); - assert!(p.errors.len() != 0); + assert!(!p.errors.is_empty()); } #[test] diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 5c10641e85..02c4a23399 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -804,7 +804,7 @@ fn format_option(opt: &OptGroup) -> String { } // Use short_name is possible, but fallback to long_name. - if opt.short_name.len() > 0 { + if !opt.short_name.is_empty() { line.push('-'); line.push_str(&opt.short_name[..]); } else { diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 44d689059d..0921c1f6cd 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -863,13 +863,16 @@ pub mod types { pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_storage { + #[derive(Copy)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], pub __ss_align: i64, pub __ss_pad2: [u8; 112], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, @@ -917,11 +920,14 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_un { + #[derive(Copy)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, @@ -1125,13 +1131,16 @@ pub mod types { pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_storage { + #[derive(Copy)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], pub __ss_align: i64, pub __ss_pad2: [u8; 112], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, @@ -1179,11 +1188,14 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_un { + #[derive(Copy)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, @@ -1405,13 +1417,16 @@ pub mod types { pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_storage { + #[derive(Copy)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], pub __ss_pad2: i64, pub __ss_pad3: [u8; 240], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, @@ -1459,11 +1474,14 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy, Clone)] pub struct sockaddr_un { + #[derive(Copy)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } #[repr(C)] #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, @@ -2838,6 +2856,7 @@ pub mod consts { pub const O_APPEND : c_int = 1024; pub const O_CREAT : c_int = 64; pub const O_EXCL : c_int = 128; + pub const O_NOCTTY : c_int = 256; pub const O_TRUNC : c_int = 512; pub const S_IFIFO : mode_t = 4096; pub const S_IFCHR : mode_t = 8192; @@ -3059,6 +3078,7 @@ pub mod consts { pub const O_APPEND : c_int = 8; pub const O_CREAT : c_int = 256; pub const O_EXCL : c_int = 1024; + pub const O_NOCTTY : c_int = 2048; pub const O_TRUNC : c_int = 512; pub const S_IFIFO : mode_t = 4096; pub const S_IFCHR : mode_t = 8192; @@ -3116,7 +3136,7 @@ pub mod consts { pub const MAP_FIXED : c_int = 0x0010; pub const MAP_ANON : c_int = 0x0800; - pub const MAP_FAILED : *mut c_void = -1 as *mut c_void; + pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; pub const MCL_CURRENT : c_int = 0x0001; pub const MCL_FUTURE : c_int = 0x0002; @@ -3326,6 +3346,8 @@ pub mod consts { pub const _SC_XOPEN_REALTIME : c_int = 130; pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131; + + pub const PTHREAD_CREATE_JOINABLE: c_int = 0; pub const PTHREAD_CREATE_DETACHED: c_int = 1; @@ -3709,12 +3731,14 @@ pub mod consts { pub const _SC_2_FORT_RUN : c_int = 50; pub const _SC_2_SW_DEV : c_int = 51; pub const _SC_2_LOCALEDEF : c_int = 52; + pub const _SC_NPROCESSORS_ONLN : c_int = 84; pub const _SC_2_CHAR_TERM : c_int = 95; pub const _SC_2_C_VERSION : c_int = 96; pub const _SC_2_UPE : c_int = 97; pub const _SC_XBS5_ILP32_OFF32 : c_int = 125; pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126; pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128; + } #[cfg(target_os = "nacl")] pub mod sysconf { @@ -3724,6 +3748,13 @@ pub mod consts { pub static _SC_NPROCESSORS_ONLN : c_int = 1; pub static _SC_PAGESIZE : c_int = 2; } + + #[cfg(target_os = "macos")] + pub mod sysconf { + use types::os::arch::c95::c_int; + pub static _SC_NPROCESSORS_ONLN : c_int = 58; + } + #[cfg(target_os = "android")] pub mod sysconf { use types::os::arch::c95::c_int; @@ -3795,6 +3826,7 @@ pub mod consts { pub const O_APPEND : c_int = 8; pub const O_CREAT : c_int = 512; pub const O_EXCL : c_int = 2048; + pub const O_NOCTTY : c_int = 32768; pub const O_TRUNC : c_int = 1024; pub const S_IFIFO : mode_t = 4096; pub const S_IFCHR : mode_t = 8192; @@ -3852,7 +3884,7 @@ pub mod consts { pub const MAP_FIXED : c_int = 0x0010; pub const MAP_ANON : c_int = 0x1000; - pub const MAP_FAILED : *mut c_void = -1 as *mut c_void; + pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; pub const MCL_CURRENT : c_int = 0x0001; pub const MCL_FUTURE : c_int = 0x0002; @@ -4249,6 +4281,7 @@ pub mod consts { pub const O_APPEND : c_int = 8; pub const O_CREAT : c_int = 512; pub const O_EXCL : c_int = 2048; + pub const O_NOCTTY : c_int = 32768; pub const O_TRUNC : c_int = 1024; pub const S_IFIFO : mode_t = 4096; pub const S_IFCHR : mode_t = 8192; @@ -4306,7 +4339,7 @@ pub mod consts { pub const MAP_FIXED : c_int = 0x0010; pub const MAP_ANON : c_int = 0x1000; - pub const MAP_FAILED : *mut c_void = -1 as *mut c_void; + pub const MAP_FAILED : *mut c_void = !0 as *mut c_void; pub const MCL_CURRENT : c_int = 0x0001; pub const MCL_FUTURE : c_int = 0x0002; @@ -4669,6 +4702,7 @@ pub mod consts { pub const O_APPEND : c_int = 8; pub const O_CREAT : c_int = 512; pub const O_EXCL : c_int = 2048; + pub const O_NOCTTY : c_int = 131072; pub const O_TRUNC : c_int = 1024; pub const S_IFIFO : mode_t = 4096; pub const S_IFCHR : mode_t = 8192; diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs index 46b9b2ed86..9ea680c7ef 100644 --- a/src/liblog/directive.rs +++ b/src/liblog/directive.rs @@ -45,7 +45,7 @@ pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { return (dirs, None); } mods.map(|m| { for s in m.split(',') { - if s.len() == 0 { continue } + if s.is_empty() { continue } let mut parts = s.split('='); let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { (Some(part0), None, None) => { diff --git a/src/librand/chacha.rs b/src/librand/chacha.rs index 44187a4fc9..9cd3b74e15 100644 --- a/src/librand/chacha.rs +++ b/src/librand/chacha.rs @@ -11,8 +11,6 @@ //! The ChaCha random number generator. use core::prelude::*; -use core::num::Int; -use core::num::wrapping::WrappingOps; use {Rng, SeedableRng, Rand}; const KEY_WORDS : usize = 8; // 8 words for the 256-bit key diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 2ba3164e1b..5ba6d8912f 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -56,18 +56,6 @@ impl Rand for Exp1 { /// /// This distribution has density function: `f(x) = lambda * /// exp(-lambda * x)` for `x > 0`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Exp, IndependentSample}; -/// -/// let exp = Exp::new(2.0); -/// let v = exp.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a Exp(2) distribution", v); -/// ``` #[derive(Copy, Clone)] pub struct Exp { /// `lambda` stored as `1/lambda`, since this is what we scale by. diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index d04e83e84f..1125d09653 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -37,18 +37,6 @@ use super::{IndependentSample, Sample, Exp}; /// == 1`, and using the boosting technique described in [1] for /// `shape < 1`. /// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{IndependentSample, Gamma}; -/// -/// let gamma = Gamma::new(2.0, 5.0); -/// let v = gamma.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a Gamma(2, 5) distribution", v); -/// ``` -/// /// [1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method /// for Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3 /// (September 2000), @@ -184,18 +172,6 @@ impl IndependentSample for GammaLargeShape { /// of `k` independent standard normal random variables. For other /// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2, /// 2)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{ChiSquared, IndependentSample}; -/// -/// let chi = ChiSquared::new(11.0); -/// let v = chi.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a χ²(11) distribution", v) -/// ``` pub struct ChiSquared { repr: ChiSquaredRepr, } @@ -242,18 +218,6 @@ impl IndependentSample for ChiSquared { /// This distribution is equivalent to the ratio of two normalised /// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) / /// (χ²(n)/n)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{FisherF, IndependentSample}; -/// -/// let f = FisherF::new(2.0, 32.0); -/// let v = f.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from an F(2, 32) distribution", v) -/// ``` pub struct FisherF { numer: ChiSquared, denom: ChiSquared, @@ -287,18 +251,6 @@ impl IndependentSample for FisherF { /// The Student t distribution, `t(nu)`, where `nu` is the degrees of /// freedom. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{StudentT, IndependentSample}; -/// -/// let t = StudentT::new(11.0); -/// let v = t.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a t(11) distribution", v) -/// ``` pub struct StudentT { chi: ChiSquared, dof: f64 diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 432081063c..4ea81b8e61 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -18,7 +18,7 @@ //! that do not need to record state. use core::prelude::*; -use core::num::{Float, Int}; +use core::num::Float; use core::marker::PhantomData; use {Rng, Rand}; @@ -90,24 +90,6 @@ pub struct Weighted { /// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for /// all `T`, as is `usize`, so one can store references or indices into /// another vector. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Weighted, WeightedChoice, IndependentSample}; -/// -/// let mut items = vec!(Weighted { weight: 2, item: 'a' }, -/// Weighted { weight: 4, item: 'b' }, -/// Weighted { weight: 1, item: 'c' }); -/// let wc = WeightedChoice::new(&mut items[..]); -/// let mut rng = rand::thread_rng(); -/// for _ in 0..16 { -/// // on average prints 'a' 4 times, 'b' 8 and 'c' twice. -/// println!("{}", wc.ind_sample(&mut rng)); -/// } -/// ``` pub struct WeightedChoice<'a, T:'a> { items: &'a mut [Weighted], weight_range: Range diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index fa41c3edfe..ac3fe6510e 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -72,19 +72,6 @@ impl Rand for StandardNormal { /// /// This uses the ZIGNOR variant of the Ziggurat method, see /// `StandardNormal` for more details. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{Normal, IndependentSample}; -/// -/// // mean 2, standard deviation 3 -/// let normal = Normal::new(2.0, 3.0); -/// let v = normal.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from a N(2, 9) distribution", v) -/// ``` #[derive(Copy, Clone)] pub struct Normal { mean: f64, @@ -121,19 +108,6 @@ impl IndependentSample for Normal { /// /// If `X` is log-normal distributed, then `ln(X)` is `N(mean, /// std_dev**2)` distributed. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::distributions::{LogNormal, IndependentSample}; -/// -/// // mean 2, standard deviation 3 -/// let log_normal = LogNormal::new(2.0, 3.0); -/// let v = log_normal.ind_sample(&mut rand::thread_rng()); -/// println!("{} is from an ln N(2, 9) distribution", v) -/// ``` #[derive(Copy, Clone)] pub struct LogNormal { norm: Normal diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index 347d494259..4916e305b7 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -13,8 +13,6 @@ // this is surprisingly complicated to be both generic & correct use core::prelude::PartialOrd; -use core::num::Int; -use core::num::wrapping::WrappingOps; use Rng; use distributions::{Sample, IndependentSample}; @@ -32,23 +30,6 @@ use distributions::{Sample, IndependentSample}; /// including `high`, but this may be very difficult. All the /// primitive integer types satisfy this property, and the float types /// normally satisfy it, but rounding may mean `high` can occur. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::distributions::{IndependentSample, Range}; -/// -/// fn main() { -/// let between = Range::new(10, 10000); -/// let mut rng = std::rand::thread_rng(); -/// let mut sum = 0; -/// for _ in 0..1000 { -/// sum += between.ind_sample(&mut rng); -/// } -/// println!("{}", sum); -/// } -/// ``` pub struct Range { low: X, range: X, @@ -90,7 +71,7 @@ pub trait SampleRange { } macro_rules! integer_impl { - ($ty:ty, $unsigned:ty) => { + ($ty:ident, $unsigned:ident) => { impl SampleRange for $ty { // we play free and fast with unsigned vs signed here // (when $ty is signed), but that's fine, since the @@ -100,7 +81,7 @@ macro_rules! integer_impl { fn construct_range(low: $ty, high: $ty) -> Range<$ty> { let range = (high as $unsigned).wrapping_sub(low as $unsigned); - let unsigned_max: $unsigned = Int::max_value(); + let unsigned_max: $unsigned = $unsigned::max_value(); // this is the largest number that fits into $unsigned // that `range` divides evenly, so, if we've sampled @@ -165,7 +146,6 @@ float_impl! { f64 } #[cfg(test)] mod tests { - use std::num::Int; use std::prelude::v1::*; use distributions::{Sample, IndependentSample}; use super::Range as Range; @@ -185,11 +165,11 @@ mod tests { fn test_integers() { let mut rng = ::test::rng(); macro_rules! t { - ($($ty:ty),*) => {{ + ($($ty:ident),*) => {{ $( let v: &[($ty, $ty)] = &[(0, 10), (10, 127), - (Int::min_value(), Int::max_value())]; + ($ty::min_value(), $ty::max_value())]; for &(low, high) in v { let mut sampler: Range<$ty> = Range::new(low, high); for _ in 0..1000 { diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 15d3d981eb..53ea28f0c1 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -24,15 +24,13 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/", html_playground_url = "http://play.rust-lang.org/")] -#![feature(no_std)] #![no_std] -#![unstable(feature = "rand")] -#![feature(staged_api)] #![staged_api] +#![unstable(feature = "rand")] #![feature(core)] +#![feature(no_std)] +#![feature(staged_api)] #![feature(step_by)] -#![deprecated(reason = "use the crates.io `rand` library instead", - since = "1.0.0-alpha")] #![cfg_attr(test, feature(test, rand, rustc_private))] @@ -145,17 +143,6 @@ pub trait Rng : Sized { /// with new data, and may panic if this is impossible /// (e.g. reading past the end of a file that is being used as the /// source of randomness). - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand, core)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut v = [0; 13579]; - /// thread_rng().fill_bytes(&mut v); - /// println!("{:?}", &v[..]); - /// ``` fn fill_bytes(&mut self, dest: &mut [u8]) { // this could, in theory, be done by transmuting dest to a // [u64], but this is (1) likely to be undefined behaviour for @@ -181,18 +168,6 @@ pub trait Rng : Sized { } /// Return a random value of a `Rand` type. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let x: usize = rng.gen(); - /// println!("{}", x); - /// println!("{:?}", rng.gen::<(f64, bool)>()); - /// ``` #[inline(always)] fn gen(&mut self) -> T { Rand::rand(self) @@ -200,19 +175,6 @@ pub trait Rng : Sized { /// Return an iterator that will yield an infinite number of randomly /// generated items. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let x = rng.gen_iter::().take(10).collect::>(); - /// println!("{:?}", x); - /// println!("{:?}", rng.gen_iter::<(f64, bool)>().take(5) - /// .collect::>()); - /// ``` fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> { Generator { rng: self, _marker: PhantomData } } @@ -228,50 +190,17 @@ pub trait Rng : Sized { /// # Panics /// /// Panics if `low >= high`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let n: usize = rng.gen_range(0, 10); - /// println!("{}", n); - /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64); - /// println!("{}", m); - /// ``` fn gen_range(&mut self, low: T, high: T) -> T { assert!(low < high, "Rng.gen_range called with low >= high"); Range::new(low, high).ind_sample(self) } /// Return a bool with a 1 in n chance of true - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// println!("{}", rng.gen_weighted_bool(3)); - /// ``` fn gen_weighted_bool(&mut self, n: usize) -> bool { n <= 1 || self.gen_range(0, n) == 0 } /// Return an iterator of random characters from the set A-Z,a-z,0-9. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let s: String = thread_rng().gen_ascii_chars().take(10).collect(); - /// println!("{}", s); - /// ``` fn gen_ascii_chars<'a>(&'a mut self) -> AsciiGenerator<'a, Self> { AsciiGenerator { rng: self } } @@ -279,18 +208,6 @@ pub trait Rng : Sized { /// Return a random element from `values`. /// /// Return `None` if `values` is empty. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let choices = [1, 2, 4, 8, 16, 32]; - /// let mut rng = thread_rng(); - /// println!("{:?}", rng.choose(&choices)); - /// assert_eq!(rng.choose(&choices[..0]), None); - /// ``` fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> { if values.is_empty() { None @@ -300,20 +217,6 @@ pub trait Rng : Sized { } /// Shuffle a mutable slice in place. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand, core)] - /// use std::rand::{thread_rng, Rng}; - /// - /// let mut rng = thread_rng(); - /// let mut y = [1, 2, 3]; - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// rng.shuffle(&mut y); - /// println!("{:?}", y); - /// ``` fn shuffle(&mut self, values: &mut [T]) { let mut i = values.len(); while i >= 2 { @@ -364,33 +267,9 @@ impl<'a, R: Rng> Iterator for AsciiGenerator<'a, R> { /// the same stream of randomness multiple times. pub trait SeedableRng: Rng { /// Reseed an RNG with the given seed. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// rng.reseed(&[5, 6, 7, 8]); - /// println!("{}", rng.gen::()); - /// ``` fn reseed(&mut self, Seed); /// Create a new RNG with the given seed. - /// - /// # Examples - /// - /// ``` - /// # #![feature(rand)] - /// use std::rand::{Rng, SeedableRng, StdRng}; - /// - /// let seed: &[_] = &[1, 2, 3, 4]; - /// let mut rng: StdRng = SeedableRng::from_seed(seed); - /// println!("{}", rng.gen::()); - /// ``` fn from_seed(seed: Seed) -> Self; } @@ -486,16 +365,6 @@ impl Rand for XorShiftRng { /// Use `Closed01` for the closed interval `[0,1]`, and the default /// `Rand` implementation for `f32` and `f64` for the half-open /// `[0,1)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{random, Open01}; -/// -/// let Open01(val) = random::>(); -/// println!("f32 from (0,1): {}", val); -/// ``` pub struct Open01(pub F); /// A wrapper for generating floating point numbers uniformly in the @@ -504,31 +373,17 @@ pub struct Open01(pub F); /// Use `Open01` for the closed interval `(0,1)`, and the default /// `Rand` implementation of `f32` and `f64` for the half-open /// `[0,1)`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{random, Closed01}; -/// -/// let Closed01(val) = random::>(); -/// println!("f32 from [0,1]: {}", val); -/// ``` pub struct Closed01(pub F); #[cfg(test)] mod test { - use std::rand; + use std::__rand as rand; pub struct MyRng { inner: R } impl ::Rng for MyRng { fn next_u32(&mut self) -> u32 { - fn next(t: &mut T) -> u32 { - use std::rand::Rng; - t.next_u32() - } - next(&mut self.inner) + rand::Rng::next_u32(&mut self.inner) } } @@ -536,7 +391,7 @@ mod test { MyRng { inner: rand::thread_rng() } } - pub fn weak_rng() -> MyRng { - MyRng { inner: rand::weak_rng() } + pub fn weak_rng() -> MyRng { + MyRng { inner: rand::thread_rng() } } } diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index e2a5276cc7..2f37451ecb 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -211,55 +211,3 @@ impl Rand for Option { } } } - -#[cfg(test)] -mod tests { - use std::rand::{Rng, thread_rng, Open01, Closed01}; - - struct ConstantRng(u64); - impl Rng for ConstantRng { - fn next_u32(&mut self) -> u32 { - let ConstantRng(v) = *self; - v as u32 - } - fn next_u64(&mut self) -> u64 { - let ConstantRng(v) = *self; - v - } - } - - #[test] - fn floating_point_edge_cases() { - // the test for exact equality is correct here. - assert!(ConstantRng(0xffff_ffff).gen::() != 1.0); - assert!(ConstantRng(0xffff_ffff_ffff_ffff).gen::() != 1.0); - } - - #[test] - fn rand_open() { - // this is unlikely to catch an incorrect implementation that - // generates exactly 0 or 1, but it keeps it sane. - let mut rng = thread_rng(); - for _ in 0..1_000 { - // strict inequalities - let Open01(f) = rng.gen::>(); - assert!(0.0 < f && f < 1.0); - - let Open01(f) = rng.gen::>(); - assert!(0.0 < f && f < 1.0); - } - } - - #[test] - fn rand_closed() { - let mut rng = thread_rng(); - for _ in 0..1_000 { - // strict inequalities - let Closed01(f) = rng.gen::>(); - assert!(0.0 <= f && f <= 1.0); - - let Closed01(f) = rng.gen::>(); - assert!(0.0 <= f && f <= 1.0); - } - } -} diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index 98d1bbf5af..ea084b2816 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -14,7 +14,6 @@ use core::prelude::*; use {Rng, SeedableRng}; -use core::default::Default; /// How many bytes of entropy the underling RNG is allowed to generate /// before it is reseeded. @@ -99,34 +98,6 @@ impl, Rsdr: Reseeder + Default> } /// Something that can be used to reseed an RNG via `ReseedingRng`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{Rng, SeedableRng, StdRng}; -/// use std::rand::reseeding::{Reseeder, ReseedingRng}; -/// -/// struct TickTockReseeder { tick: bool } -/// impl Reseeder for TickTockReseeder { -/// fn reseed(&mut self, rng: &mut StdRng) { -/// let val = if self.tick {0} else {1}; -/// rng.reseed(&[val]); -/// self.tick = !self.tick; -/// } -/// } -/// fn main() { -/// let rsdr = TickTockReseeder { tick: true }; -/// -/// let inner = StdRng::new().unwrap(); -/// let mut rng = ReseedingRng::new(inner, 10, rsdr); -/// -/// // this will repeat, because it gets reseeded very regularly. -/// let s: String = rng.gen_ascii_chars().take(100).collect(); -/// println!("{}", s); -/// } -/// -/// ``` pub trait Reseeder { /// Reseed the given RNG. fn reseed(&mut self, rng: &mut R); @@ -154,7 +125,6 @@ mod test { use core::iter::{order, repeat}; use super::{ReseedingRng, ReseedWithDefault}; - use std::default::Default; use {SeedableRng, Rng}; struct Counter { diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index e2875ac8ca..b793839703 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -836,7 +836,6 @@ pub mod writer { use std::io::prelude::*; use std::io::{self, SeekFrom, Cursor}; use std::slice::bytes; - use std::num::ToPrimitive; use super::{ EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8, @@ -1070,10 +1069,10 @@ pub mod writer { impl<'a> Encoder<'a> { // used internally to emit things like the vector length and so on fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { - if let Some(v) = v.to_u8() { - self.wr_tagged_raw_u8(EsSub8 as usize, v) - } else if let Some(v) = v.to_u32() { - self.wr_tagged_raw_u32(EsSub32 as usize, v) + if v as u8 as usize == v { + self.wr_tagged_raw_u8(EsSub8 as usize, v as u8) + } else if v as u32 as usize == v { + self.wr_tagged_raw_u32(EsSub32 as usize, v as u32) } else { Err(io::Error::new(io::ErrorKind::Other, &format!("length or variant id too big: {}", @@ -1101,21 +1100,24 @@ pub mod writer { self.emit_u64(v as u64) } fn emit_u64(&mut self, v: u64) -> EncodeResult { - match v.to_u32() { - Some(v) => self.emit_u32(v), - None => self.wr_tagged_raw_u64(EsU64 as usize, v) + if v as u32 as u64 == v { + self.emit_u32(v as u32) + } else { + self.wr_tagged_raw_u64(EsU64 as usize, v) } } fn emit_u32(&mut self, v: u32) -> EncodeResult { - match v.to_u16() { - Some(v) => self.emit_u16(v), - None => self.wr_tagged_raw_u32(EsU32 as usize, v) + if v as u16 as u32 == v { + self.emit_u16(v as u16) + } else { + self.wr_tagged_raw_u32(EsU32 as usize, v) } } fn emit_u16(&mut self, v: u16) -> EncodeResult { - match v.to_u8() { - Some(v) => self.emit_u8(v), - None => self.wr_tagged_raw_u16(EsU16 as usize, v) + if v as u8 as u16 == v { + self.emit_u8(v as u8) + } else { + self.wr_tagged_raw_u16(EsU16 as usize, v) } } fn emit_u8(&mut self, v: u8) -> EncodeResult { @@ -1126,21 +1128,24 @@ pub mod writer { self.emit_i64(v as i64) } fn emit_i64(&mut self, v: i64) -> EncodeResult { - match v.to_i32() { - Some(v) => self.emit_i32(v), - None => self.wr_tagged_raw_i64(EsI64 as usize, v) + if v as i32 as i64 == v { + self.emit_i32(v as i32) + } else { + self.wr_tagged_raw_i64(EsI64 as usize, v) } } fn emit_i32(&mut self, v: i32) -> EncodeResult { - match v.to_i16() { - Some(v) => self.emit_i16(v), - None => self.wr_tagged_raw_i32(EsI32 as usize, v) + if v as i16 as i32 == v { + self.emit_i16(v as i16) + } else { + self.wr_tagged_raw_i32(EsI32 as usize, v) } } fn emit_i16(&mut self, v: i16) -> EncodeResult { - match v.to_i8() { - Some(v) => self.emit_i8(v), - None => self.wr_tagged_raw_i16(EsI16 as usize, v) + if v as i8 as i16 == v { + self.emit_i8(v as i8) + } else { + self.wr_tagged_raw_i16(EsI16 as usize, v) } } fn emit_i8(&mut self, v: i8) -> EncodeResult { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 0a29ed90ad..938a74382e 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -10,51 +10,228 @@ #![allow(non_snake_case)] +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. register_long_diagnostics! { - E0001: r##" - This error suggests that the expression arm corresponding to the noted pattern - will never be reached as for all possible values of the expression being matched, - one of the preceding patterns will match. - This means that perhaps some of the preceding patterns are too general, this - one is too specific or the ordering is incorrect. +E0001: r##" +This error suggests that the expression arm corresponding to the noted pattern +will never be reached as for all possible values of the expression being +matched, one of the preceding patterns will match. + +This means that perhaps some of the preceding patterns are too general, this one +is too specific or the ordering is incorrect. +"##, + +E0002: r##" +This error indicates that an empty match expression is illegal because the type +it is matching on is non-empty (there exist values of this type). In safe code +it is impossible to create an instance of an empty type, so empty match +expressions are almost never desired. This error is typically fixed by adding +one or more cases to the match expression. + +An example of an empty type is `enum Empty { }`. +"##, + +E0003: r##" +Not-a-Number (NaN) values cannot be compared for equality and hence can never +match the input to a match expression. To match against NaN values, you should +instead use the `is_nan` method in a guard, as in: x if x.is_nan() => ... +"##, + +E0004: r##" +This error indicates that the compiler cannot guarantee a matching pattern for +one or more possible inputs to a match expression. Guaranteed matches are +required in order to assign values to match expressions, or alternatively, +determine the flow of execution. + +If you encounter this error you must alter your patterns so that every possible +value of the input type is matched. For types with a small number of variants +(like enums) you should probably cover all cases explicitly. Alternatively, the +underscore `_` wildcard pattern can be added after all other patterns to match +"anything else". +"##, + +// FIXME: Remove duplication here? +E0005: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee that a +name will be extracted in all cases. If you encounter this error you probably need +to use a `match` or `if let` to deal with the possibility of failure. +"##, + +E0006: r##" +Patterns used to bind names must be irrefutable, that is, they must guarantee that a +name will be extracted in all cases. If you encounter this error you probably need +to use a `match` or `if let` to deal with the possibility of failure. +"##, + +E0007: r##" +This error indicates that the bindings in a match arm would require a value to +be moved into more than one location, thus violating unique ownership. Code like +the following is invalid as it requires the entire Option to be moved +into a variable called `op_string` while simultaneously requiring the inner +String to be moved into a variable called `s`. + +let x = Some("s".to_string()); +match x { + op_string @ Some(s) => ... + None => ... +} + +See also Error 303. +"##, + +E0008: r##" +Names bound in match arms retain their type in pattern guards. As such, if a +name is bound by move in a pattern, it should also be moved to wherever it is +referenced in the pattern guard code. Doing so however would prevent the name +from being available in the body of the match arm. Consider the following: + +match Some("hi".to_string()) { + Some(s) if s.len() == 0 => // use s. + ... +} + +The variable `s` has type String, and its use in the guard is as a variable of +type String. The guard code effectively executes in a separate scope to the body +of the arm, so the value would be moved into this anonymous scope and therefore +become unavailable in the body of the arm. Although this example seems +innocuous, the problem is most clear when considering functions that take their +argument by value. + +match Some("hi".to_string()) { + Some(s) if { drop(s); false } => (), + Some(s) => // use s. + ... +} + +The value would be dropped in the guard then become unavailable not only in the +body of that arm but also in all subsequent arms! The solution is to bind by +reference when using guards or refactor the entire expression, perhaps by +putting the condition inside the body of the arm. +"##, + +E0162: r##" +An if-let pattern attempts to match the pattern, and enters the body if the +match was succesful. If the match is irrefutable (when it cannot fail to match), +use a regular `let`-binding instead. For instance: + +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +if let Irrefutable(x) = irr { + // This body will always be executed. + foo(x); +} + +// Try this instead: +let Irrefutable(x) = irr; +foo(x); "##, - E0003: r##" - Not-a-Number (NaN) values can not be compared for equality and hence can never match - the input to a match expression. To match against NaN values, you should instead use - the `is_nan` method in a guard, as in: x if x.is_nan() => ... +E0165: r##" +A while-let pattern attempts to match the pattern, and enters the body if the +match was succesful. If the match is irrefutable (when it cannot fail to match), +use a regular `let`-binding inside a `loop` instead. For instance: + +struct Irrefutable(i32); +let irr = Irrefutable(0); + +// This fails to compile because the match is irrefutable. +while let Irrefutable(x) = irr { + ... +} + +// Try this instead: +loop { + let Irrefutable(x) = irr; + ... +} "##, - E0004: r##" - This error indicates that the compiler can not guarantee a matching pattern for one - or more possible inputs to a match expression. Guaranteed matches are required in order - to assign values to match expressions, or alternatively, determine the flow of execution. +E0297: r##" +Patterns used to bind names must be irrefutable. That is, they must guarantee +that a name will be extracted in all cases. Instead of pattern matching the +loop variable, consider using a `match` or `if let` inside the loop body. For +instance: + +// This fails because `None` is not covered. +for Some(x) in xs { + ... +} + +// Match inside the loop instead: +for item in xs { + match item { + Some(x) => ... + None => ... + } +} - If you encounter this error you must alter your patterns so that every possible value of - the input type is matched. For types with a small number of variants (like enums) you - should probably cover all cases explicitly. Alternatively, the underscore `_` wildcard - pattern can be added after all other patterns to match "anything else". +// Or use `if let`: +for item in xs { + if let Some(x) = item { + ... + } +} "##, - // FIXME: Remove duplication here? - E0005: r##" - Patterns used to bind names must be irrefutable, that is, they must guarantee that a - name will be extracted in all cases. If you encounter this error you probably need - to use a `match` or `if let` to deal with the possibility of failure. +E0301: r##" +Mutable borrows are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if mutable +borrows were allowed: + +match Some(()) { + None => { }, + option if option.take().is_none() => { /* impossible, option is `Some` */ }, + Some(_) => { } // When the previous match failed, the option became `None`. +} +"##, + +E0302: r##" +Assignments are not allowed in pattern guards, because matching cannot have +side effects. Side effects could alter the matched object or the environment +on which the match depends in such a way, that the match would not be +exhaustive. For instance, the following would not match any arm if assignments +were allowed: + +match Some(()) { + None => { }, + option if { option = None; false } { }, + Some(_) => { } // When the previous match failed, the option became `None`. +} "##, - E0006: r##" - Patterns used to bind names must be irrefutable, that is, they must guarantee that a - name will be extracted in all cases. If you encounter this error you probably need - to use a `match` or `if let` to deal with the possibility of failure. +E0303: r##" +In certain cases it is possible for sub-bindings to violate memory safety. +Updates to the borrow checker in a future version of Rust may remove this +restriction, but for now patterns must be rewritten without sub-bindings. + +// Code like this... +match Some(5) { + ref op_num @ Some(num) => ... + None => ... +} + +// ... should be updated to code like this. +match Some(5) { + Some(num) => { + let op_num = &Some(num); + ... + } + None => ... +} + +See also https://github.com/rust-lang/rust/issues/14587 "## + } register_diagnostics! { - E0002, - E0007, - E0008, E0009, E0010, E0011, @@ -82,8 +259,6 @@ register_diagnostics! { E0152, E0158, E0161, - E0162, - E0165, E0170, E0261, // use of undeclared lifetime name E0262, // illegal lifetime parameter name @@ -111,13 +286,9 @@ register_diagnostics! { E0284, // cannot resolve type E0285, // overflow evaluation builtin bounds E0296, // malformed recursion limit attribute - E0297, // refutable pattern in for loop binding E0298, // mismatched types between arms E0299, // mismatched types between arms E0300, // unexpanded macro - E0301, // cannot mutable borrow in a pattern guard - E0302, // cannot assign in a pattern guard - E0303, // pattern bindings are not allowed after an `@` E0304, // expected signed integer constant E0305, // expected constant E0306, // expected positive integer for repeat count diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a4bb17bc35..32794e9793 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -68,6 +68,9 @@ extern crate test; pub use rustc_llvm as llvm; +#[macro_use] +mod macros; + // NB: This module needs to be declared first so diagnostics are // registered before they are used. pub mod diagnostics; @@ -143,6 +146,7 @@ pub mod util { pub mod nodemap; pub mod snapshot_vec; pub mod lev_distance; + pub mod num; } pub mod lib { diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs new file mode 100644 index 0000000000..ed764ebd9f --- /dev/null +++ b/src/librustc/macros.rs @@ -0,0 +1,46 @@ +// 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. + +macro_rules! enum_from_u32 { + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident = $e:expr,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant = $e),* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + }; + ($(#[$attr:meta])* pub enum $name:ident { + $($variant:ident,)* + }) => { + $(#[$attr])* + pub enum $name { + $($variant,)* + } + + impl $name { + pub fn from_u32(u: u32) -> Option<$name> { + $(if u == $name::$variant as u32 { + return Some($name::$variant) + })* + None + } + } + } +} diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index cda0084768..06a40f1dd2 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -116,37 +116,39 @@ pub const tag_items_data_item_reexport_def_id: usize = 0x47; pub const tag_items_data_item_reexport_name: usize = 0x48; // used to encode crate_ctxt side tables -#[derive(Copy, Clone, PartialEq, FromPrimitive)] -#[repr(usize)] -pub enum astencode_tag { // Reserves 0x50 -- 0x6f - tag_ast = 0x50, - - tag_tree = 0x51, - - tag_id_range = 0x52, - - tag_table = 0x53, - // GAP 0x54, 0x55 - tag_table_def = 0x56, - tag_table_node_type = 0x57, - tag_table_item_subst = 0x58, - tag_table_freevars = 0x59, - tag_table_tcache = 0x5a, - tag_table_param_defs = 0x5b, - tag_table_mutbl = 0x5c, - tag_table_last_use = 0x5d, - tag_table_spill = 0x5e, - tag_table_method_map = 0x5f, - tag_table_vtable_map = 0x60, - tag_table_adjustments = 0x61, - tag_table_moves_map = 0x62, - tag_table_capture_map = 0x63, - tag_table_closure_tys = 0x64, - tag_table_closure_kinds = 0x65, - tag_table_upvar_capture_map = 0x66, - tag_table_capture_modes = 0x67, - tag_table_object_cast_map = 0x68, - tag_table_const_qualif = 0x69, +enum_from_u32! { + #[derive(Copy, Clone, PartialEq)] + #[repr(usize)] + pub enum astencode_tag { // Reserves 0x50 -- 0x6f + tag_ast = 0x50, + + tag_tree = 0x51, + + tag_id_range = 0x52, + + tag_table = 0x53, + // GAP 0x54, 0x55 + tag_table_def = 0x56, + tag_table_node_type = 0x57, + tag_table_item_subst = 0x58, + tag_table_freevars = 0x59, + tag_table_tcache = 0x5a, + tag_table_param_defs = 0x5b, + tag_table_mutbl = 0x5c, + tag_table_last_use = 0x5d, + tag_table_spill = 0x5e, + tag_table_method_map = 0x5f, + tag_table_vtable_map = 0x60, + tag_table_adjustments = 0x61, + tag_table_moves_map = 0x62, + tag_table_capture_map = 0x63, + tag_table_closure_tys = 0x64, + tag_table_closure_kinds = 0x65, + tag_table_upvar_capture_map = 0x66, + tag_table_capture_modes = 0x67, + tag_table_object_cast_map = 0x68, + tag_table_const_qualif = 0x69, + } } pub const tag_item_trait_item_sort: usize = 0x70; diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index b6a8525675..802c581539 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -80,7 +80,7 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { (None, Some(sess)) => sess.err(s), } }; - if s.len() == 0 { + if s.is_empty() { say("crate name must not be empty"); } for c in s.chars() { @@ -528,7 +528,10 @@ impl<'a> CrateReader<'a> { source_name.clone(), body); let lo = p.span.lo; - let body = p.parse_all_token_trees(); + let body = match p.parse_all_token_trees() { + Ok(body) => body, + Err(err) => panic!(err), + }; let span = mk_sp(lo, p.last_span.hi); p.abort_if_errors(); macros.push(ast::MacroDef { diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 811aa21a0b..1f18b13fc4 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -68,11 +68,13 @@ pub enum LinkagePreference { RequireStatic, } -#[derive(Copy, Clone, PartialEq, FromPrimitive)] -pub enum NativeLibraryKind { - NativeStatic, // native static library (.a archive) - NativeFramework, // OSX-specific - NativeUnknown, // default way to specify a dynamic library +enum_from_u32! { + #[derive(Copy, Clone, PartialEq)] + pub enum NativeLibraryKind { + NativeStatic, // native static library (.a archive) + NativeFramework, // OSX-specific + NativeUnknown, // default way to specify a dynamic library + } } // Where a crate came from on the local filesystem. One of these two options diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 92810b407f..cbd5425677 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -35,7 +35,6 @@ use std::collections::HashMap; use std::hash::{self, Hash, SipHasher}; use std::io::prelude::*; use std::io; -use std::num::FromPrimitive; use std::rc::Rc; use std::slice::bytes; use std::str; @@ -763,11 +762,11 @@ pub fn get_enum_variants<'tcx>(intr: Rc, cdata: Cmd, id: ast::Nod let arg_tys = get_struct_fields(intr.clone(), cdata, did.node) .iter() .map(|field_ty| { - arg_names.push(ast::Ident::new(field_ty.name)); + arg_names.push(field_ty.name); get_type(cdata, field_ty.id.node, tcx).ty }) .collect(); - let arg_names = if arg_names.len() == 0 { None } else { Some(arg_names) }; + let arg_names = if arg_names.is_empty() { None } else { Some(arg_names) }; (None, arg_tys, arg_names) } @@ -1349,7 +1348,7 @@ pub fn get_native_libraries(cdata: Cmd) let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); let kind: cstore::NativeLibraryKind = - FromPrimitive::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); + cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); let name = name_doc.as_str().to_string(); result.push((kind, name)); true @@ -1359,7 +1358,7 @@ pub fn get_native_libraries(cdata: Cmd) pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) - .map(|doc| FromPrimitive::from_u32(reader::doc_as_u32(doc)).unwrap()) + .map(|doc| reader::doc_as_u32(doc)) } pub fn each_exported_macro(data: &[u8], intr: &IdentInterner, mut f: F) where @@ -1383,7 +1382,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) debug!("found dylib deps: {}", formats.as_str_slice()); for spec in formats.as_str_slice().split(',') { - if spec.len() == 0 { continue } + if spec.is_empty() { continue } let cnum = spec.split(':').nth(0).unwrap(); let link = spec.split(':').nth(1).unwrap(); let cnum: ast::CrateNum = cnum.parse().unwrap(); @@ -1407,7 +1406,7 @@ pub fn get_missing_lang_items(cdata: Cmd) let mut result = Vec::new(); reader::tagged_docs(items, tag_lang_items_missing, |missing_docs| { let item: lang_items::LangItem = - FromPrimitive::from_u32(reader::doc_as_u32(missing_docs)).unwrap(); + lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap(); result.push(item); true }); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 862ced78c0..29270bd6c6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -87,8 +87,8 @@ fn encode_name(rbml_w: &mut Encoder, name: ast::Name) { rbml_w.wr_tagged_str(tag_paths_data_name, &token::get_name(name)); } -fn encode_impl_type_basename(rbml_w: &mut Encoder, name: ast::Ident) { - rbml_w.wr_tagged_str(tag_item_impl_type_basename, &token::get_ident(name)); +fn encode_impl_type_basename(rbml_w: &mut Encoder, name: ast::Name) { + rbml_w.wr_tagged_str(tag_item_impl_type_basename, &token::get_name(name)); } pub fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { @@ -469,7 +469,7 @@ fn each_auxiliary_node_id(item: &ast::Item, callback: F) -> bool where ast::ItemStruct(ref struct_def, _) => { // If this is a newtype struct, return the constructor. match struct_def.ctor_id { - Some(ctor_id) if struct_def.fields.len() > 0 && + Some(ctor_id) if !struct_def.fields.is_empty() && struct_def.fields[0].node.kind.is_unnamed() => { continue_ = callback(ctor_id); } @@ -519,12 +519,12 @@ fn encode_info_for_mod(ecx: &EncodeContext, attrs: &[ast::Attribute], id: NodeId, path: PathElems, - name: ast::Ident, + name: ast::Name, vis: ast::Visibility) { rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, local_def(id)); encode_family(rbml_w, 'm'); - encode_name(rbml_w, name.name); + encode_name(rbml_w, name); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. @@ -666,7 +666,7 @@ fn encode_info_for_struct(ecx: &EncodeContext, fn encode_info_for_struct_ctor(ecx: &EncodeContext, rbml_w: &mut Encoder, - name: ast::Ident, + name: ast::Name, ctor_id: NodeId, index: &mut Vec>, struct_id: NodeId) { @@ -679,7 +679,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext, encode_def_id(rbml_w, local_def(ctor_id)); encode_family(rbml_w, 'o'); encode_bounds_and_type_for_item(rbml_w, ecx, ctor_id); - encode_name(rbml_w, name.name); + encode_name(rbml_w, name); ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path)); encode_parent_item(rbml_w, local_def(struct_id)); @@ -886,7 +886,7 @@ fn encode_method_argument_names(rbml_w: &mut Encoder, for arg in &decl.inputs { let tag = tag_method_argument_name; if let ast::PatIdent(_, ref path1, _) = arg.pat.node { - let name = token::get_ident(path1.node); + let name = token::get_name(path1.node.name); rbml_w.wr_tagged_bytes(tag, name.as_bytes()); } else { rbml_w.wr_tagged_bytes(tag, &[]); @@ -1044,7 +1044,7 @@ fn encode_info_for_item(ecx: &EncodeContext, &item.attrs, item.id, path, - item.ident, + item.ident.name, item.vis); } ast::ItemForeignMod(ref fm) => { @@ -1152,7 +1152,7 @@ fn encode_info_for_item(ecx: &EncodeContext, // If this is a tuple-like struct, encode the type of the constructor. match struct_def.ctor_id { Some(ctor_id) => { - encode_info_for_struct_ctor(ecx, rbml_w, item.ident, + encode_info_for_struct_ctor(ecx, rbml_w, item.ident.name, ctor_id, index, def_id.node); } None => {} @@ -1187,8 +1187,8 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_polarity(rbml_w, polarity); match ty.node { ast::TyPath(None, ref path) if path.segments.len() == 1 => { - let ident = path.segments.last().unwrap().identifier; - encode_impl_type_basename(rbml_w, ident); + let name = path.segments.last().unwrap().identifier.name; + encode_impl_type_basename(rbml_w, name); } _ => {} } @@ -1264,7 +1264,8 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_paren_sugar(rbml_w, trait_def.paren_sugar); encode_defaulted(rbml_w, ty::trait_has_default_impl(tcx, def_id)); encode_associated_type_names(rbml_w, &trait_def.associated_type_names); - encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics); + encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, + tag_item_generics); encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id), tag_item_super_predicates); encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref); @@ -1513,7 +1514,7 @@ fn encode_info_for_items(ecx: &EncodeContext, &[], ast::CRATE_NODE_ID, [].iter().cloned().chain(LinkedPath::empty()), - syntax::parse::token::special_idents::invalid, + syntax::parse::token::special_idents::invalid.name, ast::Public); visit::walk_crate(&mut EncodeVisitor { @@ -1750,7 +1751,7 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { for filemap in &codemap.files.borrow()[..] { - if filemap.lines.borrow().len() == 0 || filemap.is_imported() { + if filemap.lines.borrow().is_empty() || filemap.is_imported() { // No need to export empty filemaps, as they can't contain spans // that need translation. // Also no need to re-export imported filemaps, as any downstream diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 7b63e38b58..398e4cd33b 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -129,7 +129,7 @@ //! > Dear rustc, //! > //! > When you are attempting to load the immediate dependency `crate-name`, I -//! > would like you too assume that the library is located at +//! > would like you to assume that the library is located at //! > `path/to/the/crate.rlib`, and look nowhere else. Also, please do not //! > assume that the path I specified has the name `crate-name`. //! @@ -307,13 +307,13 @@ impl<'a> Context<'a> { } pub fn report_load_errs(&mut self) { - let message = if self.rejected_via_hash.len() > 0 { + let message = if !self.rejected_via_hash.is_empty() { format!("found possibly newer version of crate `{}`", self.ident) - } else if self.rejected_via_triple.len() > 0 { + } else if !self.rejected_via_triple.is_empty() { format!("couldn't find crate `{}` with expected target triple {}", self.ident, self.triple) - } else if self.rejected_via_kind.len() > 0 { + } else if !self.rejected_via_kind.is_empty() { format!("found staticlib `{}` instead of rlib or dylib", self.ident) } else { format!("can't find crate for `{}`", self.ident) @@ -325,7 +325,7 @@ impl<'a> Context<'a> { }; self.sess.span_err(self.span, &message[..]); - if self.rejected_via_triple.len() > 0 { + if !self.rejected_via_triple.is_empty() { let mismatches = self.rejected_via_triple.iter(); for (i, &CrateMismatch{ ref path, ref got }) in mismatches.enumerate() { self.sess.fileline_note(self.span, @@ -333,7 +333,7 @@ impl<'a> Context<'a> { self.ident, i+1, got, path.display())); } } - if self.rejected_via_hash.len() > 0 { + if !self.rejected_via_hash.is_empty() { self.sess.span_note(self.span, "perhaps this crate needs \ to be recompiled?"); let mismatches = self.rejected_via_hash.iter(); @@ -353,7 +353,7 @@ impl<'a> Context<'a> { } } } - if self.rejected_via_kind.len() > 0 { + if !self.rejected_via_kind.is_empty() { self.sess.fileline_help(self.span, "please recompile this crate using \ --crate-type lib"); let mismatches = self.rejected_via_kind.iter(); @@ -517,7 +517,7 @@ impl<'a> Context<'a> { // library's metadata sections. In theory we should // read both, but reading dylib metadata is quite // slow. - if m.len() == 0 { + if m.is_empty() { return None } else if m.len() == 1 { return Some(m.into_iter().next().unwrap()) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 3fb128b188..955905ee26 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -101,10 +101,6 @@ fn scan(st: &mut PState, mut is_last: F, op: G) -> R where return op(&st.data[start_pos..end_pos]); } -pub fn parse_ident(st: &mut PState, last: char) -> ast::Ident { - ast::Ident::new(parse_name(st, last)) -} - pub fn parse_name(st: &mut PState, last: char) -> ast::Name { fn is_last(b: char, c: char) -> bool { return c == b; } parse_name_(st, |a| is_last(last, a) ) @@ -345,7 +341,12 @@ fn parse_region_(st: &mut PState, conv: &mut F) -> ty::Region where let index = parse_u32(st); assert_eq!(next(st), '|'); let nm = token::str_to_ident(&parse_str(st, ']')); - ty::ReEarlyBound(node_id, space, index, nm.name) + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: node_id, + space: space, + index: index, + name: nm.name + }) } 'f' => { assert_eq!(next(st), '['); @@ -373,6 +374,16 @@ fn parse_region_(st: &mut PState, conv: &mut F) -> ty::Region where fn parse_scope(st: &mut PState) -> region::CodeExtent { match next(st) { + 'P' => { + assert_eq!(next(st), '['); + let fn_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); + let body_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), ']'); + region::CodeExtent::ParameterScope { + fn_id: fn_id, body_id: body_id + } + } 'M' => { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Misc(node_id) @@ -382,8 +393,11 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { region::CodeExtent::DestructionScope(node_id) } 'B' => { + assert_eq!(next(st), '['); let node_id = parse_uint(st) as ast::NodeId; + assert_eq!(next(st), '|'); let first_stmt_index = parse_uint(st); + assert_eq!(next(st), ']'); let block_remainder = region::BlockRemainder { block: node_id, first_statement_index: first_stmt_index, }; diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 7a2df49662..8a27881128 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -241,12 +241,12 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { enc_bound_region(w, cx, br); mywrite!(w, "]"); } - ty::ReEarlyBound(node_id, space, index, name) => { + ty::ReEarlyBound(ref data) => { mywrite!(w, "B[{}|{}|{}|{}]", - node_id, - space.to_uint(), - index, - token::get_name(name)); + data.param_id, + data.space.to_uint(), + data.index, + token::get_name(data.name)); } ty::ReFree(ref fr) => { mywrite!(w, "f["); @@ -275,9 +275,11 @@ pub fn enc_region(w: &mut Encoder, cx: &ctxt, r: ty::Region) { fn enc_scope(w: &mut Encoder, _cx: &ctxt, scope: region::CodeExtent) { match scope { + region::CodeExtent::ParameterScope { + fn_id, body_id } => mywrite!(w, "P[{}|{}]", fn_id, body_id), region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), region::CodeExtent::Remainder(region::BlockRemainder { - block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i), + block: b, first_statement_index: i }) => mywrite!(w, "B[{}|{}]", b, i), region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b6061f3923..ee8373279d 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -41,7 +41,6 @@ use syntax; use std::cell::Cell; use std::io::SeekFrom; use std::io::prelude::*; -use std::num::FromPrimitive; use std::rc::Rc; use std::fmt::Debug; @@ -457,7 +456,11 @@ impl tr for def::Def { def::DefMethod(did, p) => { def::DefMethod(did.tr(dcx), p.map(|did2| did2.tr(dcx))) } - def::DefSelfTy(nid) => { def::DefSelfTy(dcx.tr_id(nid)) } + def::DefSelfTy(opt_did, impl_ids) => { def::DefSelfTy(opt_did.map(|did| did.tr(dcx)), + impl_ids.map(|(nid1, nid2)| { + (dcx.tr_id(nid1), + dcx.tr_id(nid2)) + })) } def::DefMod(did) => { def::DefMod(did.tr(dcx)) } def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) } def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) } @@ -492,8 +495,13 @@ impl tr for ty::Region { ty::ReLateBound(debruijn, br) => { ty::ReLateBound(debruijn, br.tr(dcx)) } - ty::ReEarlyBound(id, space, index, ident) => { - ty::ReEarlyBound(dcx.tr_id(id), space, index, ident) + ty::ReEarlyBound(data) => { + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: dcx.tr_id(data.param_id), + space: data.space, + index: data.index, + name: data.name, + }) } ty::ReScope(scope) => { ty::ReScope(scope.tr(dcx)) @@ -597,18 +605,18 @@ impl tr for ty::UpvarCapture { trait read_method_callee_helper<'tcx> { fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (ty::ExprAdjustment, MethodCallee<'tcx>); + -> (u32, MethodCallee<'tcx>); } fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, - adjustment: ty::ExprAdjustment, + autoderef: u32, method: &MethodCallee<'tcx>) { use serialize::Encoder; rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { - rbml_w.emit_struct_field("adjustment", 0, |rbml_w| { - adjustment.encode(rbml_w) + rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { + autoderef.encode(rbml_w) }); rbml_w.emit_struct_field("origin", 1, |rbml_w| { Ok(rbml_w.emit_method_origin(ecx, &method.origin)) @@ -624,13 +632,13 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> (ty::ExprAdjustment, MethodCallee<'tcx>) { + -> (u32, MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { - let adjustment = this.read_struct_field("adjustment", 0, |this| { + let autoderef = this.read_struct_field("autoderef", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((adjustment, MethodCallee { + Ok((autoderef, MethodCallee { origin: this.read_struct_field("origin", 1, |this| { Ok(this.read_method_origin(dcx)) }).unwrap(), @@ -684,7 +692,7 @@ pub trait vtable_decoder_helpers<'tcx> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (ty::ExprAdjustment, ty::vtable_res<'tcx>); + -> (u32, ty::vtable_res<'tcx>); fn read_vtable_res(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) -> ty::vtable_res<'tcx>; @@ -709,12 +717,12 @@ impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_vtable_res_with_key(&mut self, tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata) - -> (ty::ExprAdjustment, ty::vtable_res<'tcx>) { + -> (u32, ty::vtable_res<'tcx>) { self.read_struct("VtableWithKey", 2, |this| { - let adjustment = this.read_struct_field("adjustment", 0, |this| { + let autoderef = this.read_struct_field("autoderef", 0, |this| { Decodable::decode(this) }).unwrap(); - Ok((adjustment, this.read_struct_field("vtable_res", 1, |this| { + Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| { Ok(this.read_vtable_res(tcx, cdata)) }).unwrap())) }).unwrap() @@ -841,12 +849,9 @@ trait rbml_writer_helpers<'tcx> { fn emit_builtin_bounds(&mut self, ecx: &e::EncodeContext, bounds: &ty::BuiltinBounds); fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, adj: &ty::AutoAdjustment<'tcx>); - fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - autoref: &ty::AutoRef<'tcx>); + fn emit_autoref<'a>(&mut self, autoref: &ty::AutoRef<'tcx>); fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, auto_deref_ref: &ty::AutoDerefRef<'tcx>); - fn emit_unsize_kind<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - uk: &ty::UnsizeKind<'tcx>); } impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { @@ -1008,10 +1013,8 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_enum("AutoAdjustment", |this| { match *adj { - ty::AdjustReifyFnPointer(def_id) => { - this.emit_enum_variant("AdjustReifyFnPointer", 1, 2, |this| { - this.emit_enum_variant_arg(0, |this| def_id.encode(this)) - }) + ty::AdjustReifyFnPointer=> { + this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) } ty::AdjustUnsafeFnPointer => { @@ -1030,50 +1033,20 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { }); } - fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &ty::AutoRef<'tcx>) { + fn emit_autoref<'b>(&mut self, autoref: &ty::AutoRef<'tcx>) { use serialize::Encoder; self.emit_enum("AutoRef", |this| { match autoref { - &ty::AutoPtr(r, m, None) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, - |this| this.emit_option(|this| this.emit_option_none())) - }) - } - &ty::AutoPtr(r, m, Some(box ref a)) => { - this.emit_enum_variant("AutoPtr", 0, 3, |this| { + &ty::AutoPtr(r, m) => { + this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)); - this.emit_enum_variant_arg(2, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) - }) - } - &ty::AutoUnsize(ref uk) => { - this.emit_enum_variant("AutoUnsize", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } - &ty::AutoUnsizeUniq(ref uk) => { - this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) - }) - } - &ty::AutoUnsafe(m, None) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, - |this| this.emit_option(|this| this.emit_option_none())) + this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } - &ty::AutoUnsafe(m, Some(box ref a)) => { - this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)); - this.emit_enum_variant_arg(1, |this| this.emit_option( - |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) + &ty::AutoUnsafe(m) => { + this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)) }) } } @@ -1086,55 +1059,26 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { self.emit_struct("AutoDerefRef", 2, |this| { this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); + this.emit_struct_field("autoref", 1, |this| { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), } }) - }) - }); - } - - fn emit_unsize_kind<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - uk: &ty::UnsizeKind<'tcx>) { - use serialize::Encoder; + }); - self.emit_enum("UnsizeKind", |this| { - match *uk { - ty::UnsizeLength(len) => { - this.emit_enum_variant("UnsizeLength", 0, 1, |this| { - this.emit_enum_variant_arg(0, |this| len.encode(this)) - }) - } - ty::UnsizeStruct(box ref uk, idx) => { - this.emit_enum_variant("UnsizeStruct", 1, 2, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))); - this.emit_enum_variant_arg(1, |this| idx.encode(this)) - }) - } - ty::UnsizeVtable(ty::TyTrait { ref principal, - bounds: ref b }, - self_ty) => { - this.emit_enum_variant("UnsizeVtable", 2, 4, |this| { - this.emit_enum_variant_arg(0, |this| { - try!(this.emit_struct_field("principal", 0, |this| { - Ok(this.emit_trait_ref(ecx, &*principal.0)) - })); - this.emit_struct_field("bounds", 1, |this| { - Ok(this.emit_existential_bounds(ecx, b)) - }) - }); - this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty))) - }) - } - ty::UnsizeUpcast(target_ty) => { - this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty))) - }) - } - } + this.emit_struct_field("unsize", 2, |this| { + this.emit_option(|this| { + match auto_deref_ref.unsize { + None => this.emit_option_none(), + Some(target) => this.emit_option_some(|this| { + Ok(this.emit_ty(ecx, target)) + }) + } + }) + }) }); } } @@ -1254,7 +1198,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, if let Some(method) = tcx.method_map.borrow().get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) + encode_method_callee(ecx, rbml_w, method_call.autoderef, method) }) } @@ -1267,31 +1211,19 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, if let Some(adjustment) = tcx.adjustments.borrow().get(&id) { match *adjustment { - _ if ty::adjust_is_object(adjustment) => { - let method_call = MethodCall::autoobject(id); - if let Some(method) = tcx.method_map.borrow().get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.adjustment, method) - }) - } - } ty::AdjustDerefRef(ref adj) => { - assert!(!ty::adjust_is_object(adjustment)); for autoderef in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(id, autoderef); + let method_call = MethodCall::autoderef(id, autoderef as u32); if let Some(method) = tcx.method_map.borrow().get(&method_call) { rbml_w.tag(c::tag_table_method_map, |rbml_w| { rbml_w.id(id); encode_method_callee(ecx, rbml_w, - method_call.adjustment, method) + method_call.autoderef, method) }) } } } - _ => { - assert!(!ty::adjust_is_object(adjustment)); - } + _ => {} } rbml_w.tag(c::tag_table_adjustments, |rbml_w| { @@ -1363,8 +1295,6 @@ trait rbml_decoder_decoder_helpers<'tcx> { -> ty::AutoDerefRef<'tcx>; fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> ty::AutoRef<'tcx>; - fn read_unsize_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::UnsizeKind<'tcx>; fn convert_def_id(&mut self, dcx: &DecodeContext, source: DefIdSource, @@ -1636,18 +1566,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { - let variants = ["AutoAddEnv", "AutoDerefRef"]; + let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustDerefRef"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { - 1 => { - let def_id: ast::DefId = - this.read_def_id(dcx); - - ty::AdjustReifyFnPointer(def_id) - } - 2 => { - ty::AdjustUnsafeFnPointer - } + 1 => ty::AdjustReifyFnPointer, + 2 => ty::AdjustUnsafeFnPointer, 3 => { let auto_deref_ref: ty::AutoDerefRef = this.read_enum_variant_arg(0, @@ -1677,16 +1600,23 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { } }) }).unwrap(), + unsize: this.read_struct_field("unsize", 2, |this| { + this.read_option(|this, b| { + if b { + Ok(Some(this.read_ty(dcx))) + } else { + Ok(None) + } + }) + }).unwrap(), }) }).unwrap() } - fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> ty::AutoRef<'tcx> { + fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) + -> ty::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { - let variants = ["AutoPtr", - "AutoUnsize", - "AutoUnsizeUniq", - "AutoUnsafe"]; + let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { Ok(match i { 0 => { @@ -1694,94 +1624,16 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); let m: ast::Mutability = this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(2, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoPtr(r.tr(dcx), m, a) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - - ty::AutoUnsize(uk) - } - 2 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - ty::AutoUnsizeUniq(uk) + ty::AutoPtr(dcx.tcx.mk_region(r.tr(dcx)), m) } - 3 => { + 1 => { let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - let a: Option> = - this.read_enum_variant_arg(1, |this| this.read_option(|this, b| { - if b { - Ok(Some(box this.read_autoref(dcx))) - } else { - Ok(None) - } - })).unwrap(); - - ty::AutoUnsafe(m, a) - } - _ => panic!("bad enum variant for ty::AutoRef") - }) - }) - }).unwrap() - } - - fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::UnsizeKind<'tcx> { - self.read_enum("UnsizeKind", |this| { - let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"]; - this.read_enum_variant(variants, |this, i| { - Ok(match i { - 0 => { - let len: usize = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - ty::UnsizeLength(len) - } - 1 => { - let uk: ty::UnsizeKind = - this.read_enum_variant_arg(0, - |this| Ok(this.read_unsize_kind(dcx))).unwrap(); - let idx: usize = - this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap(); - ty::UnsizeStruct(box uk, idx) - } - 2 => { - let ty_trait = try!(this.read_enum_variant_arg(0, |this| { - let principal = try!(this.read_struct_field("principal", 0, |this| { - Ok(this.read_poly_trait_ref(dcx)) - })); - Ok(ty::TyTrait { - principal: principal, - bounds: try!(this.read_struct_field("bounds", 1, |this| { - Ok(this.read_existential_bounds(dcx)) - })), - }) - })); - let self_ty = - this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeVtable(ty_trait, self_ty) + ty::AutoUnsafe(m) } - 3 => { - let target_ty = - this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap(); - ty::UnsizeUpcast(target_ty) - } - _ => panic!("bad enum variant for ty::UnsizeKind") + _ => panic!("bad enum variant for ty::AutoRef") }) }) }).unwrap() @@ -1860,7 +1712,8 @@ fn decode_side_tables(dcx: &DecodeContext, debug!(">> Side table document with tag 0x{:x} \ found for id {} (orig {})", tag, id, id0); - let decoded_tag: Option = FromPrimitive::from_usize(tag); + let tag = tag as u32; + let decoded_tag: Option = c::astencode_tag::from_u32(tag); match decoded_tag { None => { dcx.tcx.sess.bug( @@ -1918,10 +1771,10 @@ fn decode_side_tables(dcx: &DecodeContext, dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds); } c::tag_table_method_map => { - let (adjustment, method) = val_dsr.read_method_callee(dcx); + let (autoderef, method) = val_dsr.read_method_callee(dcx); let method_call = MethodCall { expr_id: id, - adjustment: adjustment + autoderef: autoderef }; dcx.tcx.method_map.borrow_mut().insert(method_call, method); } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index ce011f2561..ee9d1e0155 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -662,7 +662,19 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> { cmt: mc::cmt<'tcx>, _loan_region: ty::Region, bk: ty::BorrowKind, - loan_cause: euv::LoanCause) { + loan_cause: euv::LoanCause) + { + // Kind of hacky, but we allow Unsafe coercions in constants. + // These occur when we convert a &T or *T to a *U, as well as + // when making a thin pointer (e.g., `*T`) into a fat pointer + // (e.g., `*Trait`). + match loan_cause { + euv::LoanCause::AutoUnsafe => { + return; + } + _ => { } + } + let mut cur = &cmt; let mut is_interior = false; loop { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 79f4d62b45..912854a6d7 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -26,7 +26,7 @@ use middle::ty::*; use middle::ty; use std::cmp::Ordering; use std::fmt; -use std::iter::{range_inclusive, AdditiveIterator, FromIterator, IntoIterator, repeat}; +use std::iter::{range_inclusive, FromIterator, IntoIterator, repeat}; use std::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId, Pat}; use syntax::ast_util; @@ -76,7 +76,7 @@ impl<'a> fmt::Debug for Matrix<'a> { pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0) }).collect(); - let total_width = column_widths.iter().cloned().sum() + column_count * 3 + 1; + let total_width = column_widths.iter().cloned().sum::() + column_count * 3 + 1; let br = repeat('+').take(total_width).collect::(); try!(write!(f, "{}\n", br)); for row in pretty_printed_matrix { @@ -239,7 +239,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) if let Some(DefLocal(_)) = def { if ty::enum_variants(cx.tcx, def_id).iter().any(|variant| token::get_name(variant.name) == token::get_name(ident.node.name) - && variant.args.len() == 0 + && variant.args.is_empty() ) { span_warn!(cx.tcx.sess, p.span, E0170, "pattern binding `{}` is named the same as one \ @@ -636,19 +636,19 @@ fn is_useful(cx: &MatchCheckCtxt, -> Usefulness { let &Matrix(ref rows) = matrix; debug!("{:?}", matrix); - if rows.len() == 0 { + if rows.is_empty() { return match witness { ConstructWitness => UsefulWithWitness(vec!()), LeaveOutWitness => Useful }; } - if rows[0].len() == 0 { + if rows[0].is_empty() { return NotUseful; } assert!(rows.iter().all(|r| r.len() == v.len())); let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) { Some(r) => raw_pat(r[0]), - None if v.len() == 0 => return NotUseful, + None if v.is_empty() => return NotUseful, None => v[0] }; let left_ty = if real_pat.id == DUMMY_NODE_ID { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 367bcbbe1d..2c6ffb3281 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -20,6 +20,7 @@ use middle::{astencode, def}; use middle::pat_util::def_to_path; use middle::ty::{self, Ty}; use middle::astconv_util::ast_ty_to_prim_ty; +use util::num::ToPrimitive; use syntax::ast::{self, Expr}; use syntax::codemap::Span; @@ -30,7 +31,6 @@ use syntax::{ast_map, ast_util, codemap}; use std::borrow::{Cow, IntoCow}; use std::num::wrapping::OverflowingOps; -use std::num::ToPrimitive; use std::cmp::Ordering; use std::collections::hash_map::Entry::Vacant; use std::{i8, i16, i32, i64}; diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index f69ac03052..41b4495c5f 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -64,8 +64,14 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> { /// bits generated as we exit the cfg node. Updated by `add_gen()`. gens: Vec, - /// bits killed as we exit the cfg node. Updated by `add_kill()`. - kills: Vec, + /// bits killed as we exit the cfg node, or non-locally jump over + /// it. Updated by `add_kill(KillFrom::ScopeEnd)`. + scope_kills: Vec, + + /// bits killed as we exit the cfg node directly; if it is jumped + /// over, e.g. via `break`, the kills are not reflected in the + /// jump's effects. Updated by `add_kill(KillFrom::Execution)`. + action_kills: Vec, /// bits that are valid on entry to the cfg node. Updated by /// `propagate()`. @@ -130,15 +136,23 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O "".to_string() }; - let kills = &self.kills[start .. end]; - let kills_str = if kills.iter().any(|&u| u != 0) { - format!(" kill: {}", bits_to_string(kills)) + let action_kills = &self.action_kills[start .. end]; + let action_kills_str = if action_kills.iter().any(|&u| u != 0) { + format!(" action_kill: {}", bits_to_string(action_kills)) + } else { + "".to_string() + }; + + let scope_kills = &self.scope_kills[start .. end]; + let scope_kills_str = if scope_kills.iter().any(|&u| u != 0) { + format!(" scope_kill: {}", bits_to_string(scope_kills)) } else { "".to_string() }; - try!(ps.synth_comment(format!("id {}: {}{}{}", id, entry_str, - gens_str, kills_str))); + try!(ps.synth_comment( + format!("id {}: {}{}{}{}", id, entry_str, + gens_str, action_kills_str, scope_kills_str))); try!(pp::space(&mut ps.s)); } Ok(()) @@ -187,6 +201,25 @@ fn build_nodeid_to_index(decl: Option<&ast::FnDecl>, } } +/// Flag used by `add_kill` to indicate whether the provided kill +/// takes effect only when control flows directly through the node in +/// question, or if the kill's effect is associated with any +/// control-flow directly through or indirectly over the node. +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum KillFrom { + /// A `ScopeEnd` kill is one that takes effect when any control + /// flow goes over the node. A kill associated with the end of the + /// scope of a variable declaration `let x;` is an example of a + /// `ScopeEnd` kill. + ScopeEnd, + + /// An `Execution` kill is one that takes effect only when control + /// flow goes through the node to completion. A kill associated + /// with an assignment statement `x = expr;` is an example of an + /// `Execution` kill. + Execution, +} + impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { pub fn new(tcx: &'a ty::ctxt<'tcx>, analysis_name: &'static str, @@ -195,7 +228,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { oper: O, id_range: IdRange, bits_per_id: usize) -> DataFlowContext<'a, 'tcx, O> { - let words_per_id = (bits_per_id + usize::BITS as usize - 1) / usize::BITS as usize; + let words_per_id = (bits_per_id + usize::BITS - 1) / usize::BITS; let num_nodes = cfg.graph.all_nodes().len(); debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \ @@ -206,8 +239,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let entry = if oper.initial_value() { usize::MAX } else {0}; - let gens: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); - let kills: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); + let zeroes: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect(); + let gens: Vec<_> = zeroes.clone(); + let kills1: Vec<_> = zeroes.clone(); + let kills2: Vec<_> = zeroes; let on_entry: Vec<_> = repeat(entry).take(num_nodes * words_per_id).collect(); let nodeid_to_index = build_nodeid_to_index(decl, cfg); @@ -220,7 +255,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { bits_per_id: bits_per_id, oper: oper, gens: gens, - kills: kills, + action_kills: kills1, + scope_kills: kills2, on_entry: on_entry } } @@ -240,7 +276,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } } - pub fn add_kill(&mut self, id: ast::NodeId, bit: usize) { + pub fn add_kill(&mut self, kind: KillFrom, id: ast::NodeId, bit: usize) { //! Indicates that `id` kills `bit` debug!("{} add_kill(id={}, bit={})", self.analysis_name, id, bit); @@ -250,7 +286,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let indices = get_cfg_indices(id, &self.nodeid_to_index); for &cfgidx in indices { let (start, end) = self.compute_id_range(cfgidx); - let kills = &mut self.kills[start.. end]; + let kills = match kind { + KillFrom::Execution => &mut self.action_kills[start.. end], + KillFrom::ScopeEnd => &mut self.scope_kills[start.. end], + }; set_bit(kills, bit); } } @@ -264,7 +303,9 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let (start, end) = self.compute_id_range(cfgidx); let gens = &self.gens[start.. end]; bitwise(bits, gens, &Union); - let kills = &self.kills[start.. end]; + let kills = &self.action_kills[start.. end]; + bitwise(bits, kills, &Subtract); + let kills = &self.scope_kills[start.. end]; bitwise(bits, kills, &Subtract); debug!("{} apply_gen_kill(cfgidx={:?}, bits={}) [after]", @@ -278,7 +319,8 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { assert!(start < self.gens.len()); assert!(end <= self.gens.len()); - assert!(self.gens.len() == self.kills.len()); + assert!(self.gens.len() == self.action_kills.len()); + assert!(self.gens.len() == self.scope_kills.len()); assert!(self.gens.len() == self.on_entry.len()); (start, end) @@ -367,7 +409,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { for (word_index, &word) in words.iter().enumerate() { if word != 0 { - let base_index = word_index * usize::BITS as usize; + let base_index = word_index * usize::BITS; for offset in 0..usize::BITS { let bit = 1 << offset; if (word & bit) != 0 { @@ -412,7 +454,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { cfg.graph.each_edge(|_edge_index, edge| { let flow_exit = edge.source(); let (start, end) = self.compute_id_range(flow_exit); - let mut orig_kills = self.kills[start.. end].to_vec(); + let mut orig_kills = self.scope_kills[start.. end].to_vec(); let mut changed = false; for &node_id in &edge.data.exiting_scopes { @@ -421,8 +463,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { Some(indices) => { for &cfg_idx in indices { let (start, end) = self.compute_id_range(cfg_idx); - let kills = &self.kills[start.. end]; + let kills = &self.scope_kills[start.. end]; if bitwise(&mut orig_kills, kills, &Union) { + debug!("scope exits: scope id={} \ + (node={:?} of {:?}) added killset: {}", + node_id, cfg_idx, indices, + bits_to_string(kills)); changed = true; } } @@ -436,7 +482,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } if changed { - let bits = &mut self.kills[start.. end]; + let bits = &mut self.scope_kills[start.. end]; debug!("{} add_kills_from_flow_exits flow_exit={:?} bits={} [before]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); bits.clone_from_slice(&orig_kills[..]); @@ -601,8 +647,8 @@ fn bitwise(out_vec: &mut [usize], fn set_bit(words: &mut [usize], bit: usize) -> bool { debug!("set_bit: words={} bit={}", mut_bits_to_string(words), bit_str(bit)); - let word = bit / usize::BITS as usize; - let bit_in_word = bit % usize::BITS as usize; + let word = bit / usize::BITS; + let bit_in_word = bit % usize::BITS; let bit_mask = 1 << bit_in_word; debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word); let oldv = words[word]; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 568375597c..2befbf9924 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -133,12 +133,12 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } } - fn handle_field_access(&mut self, lhs: &ast::Expr, name: &ast::Ident) { + fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) { match ty::expr_ty_adjusted(self.tcx, lhs).sty { ty::ty_struct(id, _) => { let fields = ty::lookup_struct_fields(self.tcx, id); let field_id = fields.iter() - .find(|field| field.name == name.name).unwrap().id; + .find(|field| field.name == name).unwrap().id; self.live_symbols.insert(field_id.node); }, _ => () @@ -182,7 +182,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn mark_live_symbols(&mut self) { let mut scanned = HashSet::new(); - while self.worklist.len() > 0 { + while !self.worklist.is_empty() { let id = self.worklist.pop().unwrap(); if scanned.contains(&id) { continue @@ -267,7 +267,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { self.lookup_and_handle_method(expr.id, expr.span); } ast::ExprField(ref lhs, ref ident) => { - self.handle_field_access(&**lhs, &ident.node); + self.handle_field_access(&**lhs, ident.node.name); } ast::ExprTupField(ref lhs, idx) => { self.handle_tup_field_access(&**lhs, idx.node); @@ -511,9 +511,9 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { fn warn_dead_code(&mut self, id: ast::NodeId, span: codemap::Span, - ident: ast::Ident, + name: ast::Name, node_type: &str) { - let name = ident.as_str(); + let name = name.as_str(); if !name.starts_with("_") { self.tcx .sess @@ -528,14 +528,19 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &ast::Item) { if self.should_warn_about_item(item) { - self.warn_dead_code(item.id, item.span, item.ident, item.node.descriptive_variant()); + self.warn_dead_code( + item.id, + item.span, + item.ident.name, + item.node.descriptive_variant() + ); } else { match item.node { ast::ItemEnum(ref enum_def, _) => { for variant in &enum_def.variants { if self.should_warn_about_variant(&variant.node) { self.warn_dead_code(variant.node.id, variant.span, - variant.node.name, "variant"); + variant.node.name.name, "variant"); } } }, @@ -547,7 +552,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { fn visit_foreign_item(&mut self, fi: &ast::ForeignItem) { if !self.symbol_is_live(fi.id, None) { - self.warn_dead_code(fi.id, fi.span, fi.ident, fi.node.descriptive_variant()); + self.warn_dead_code(fi.id, fi.span, fi.ident.name, fi.node.descriptive_variant()); } visit::walk_foreign_item(self, fi); } @@ -557,9 +562,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { span: codemap::Span, id: ast::NodeId) { // Have to warn method here because methods are not ast::Item match fk { - visit::FkMethod(name, _) => { + visit::FkMethod(name, _, _) => { if !self.symbol_is_live(id, None) { - self.warn_dead_code(id, span, name, "method"); + self.warn_dead_code(id, span, name.name, "method"); } } _ => () @@ -570,7 +575,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { fn visit_struct_field(&mut self, field: &ast::StructField) { if self.should_warn_about_field(&field.node) { self.warn_dead_code(field.node.id, field.span, - field.node.ident().unwrap(), "struct field"); + field.node.ident().unwrap().name, "struct field"); } visit::walk_struct_field(self, field); diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 6707a4d3fd..f0b3590885 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -22,7 +22,8 @@ use std::cell::RefCell; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { DefFn(ast::DefId, bool /* is_ctor */), - DefSelfTy(/* trait id */ ast::NodeId), + DefSelfTy(Option, // trait id + Option<(ast::NodeId, ast::NodeId)>), // (impl id, self type id) DefMod(ast::DefId), DefForeignMod(ast::DefId), DefStatic(ast::DefId, bool /* is_mutbl */), @@ -139,18 +140,19 @@ impl Def { DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | - DefMethod(id, _) | DefConst(id) => { + DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> { id } DefLocal(id) | - DefSelfTy(id) | DefUpvar(id, _) | DefRegion(id) | - DefLabel(id) => { + DefLabel(id) | + DefSelfTy(_, Some((_, id))) => { local_def(id) } - DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy") + DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"), + DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"), } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 814492cbef..b6a070c933 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -87,9 +87,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { block: &'v ast::Block, span: Span, _: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { - visit::FkItemFn(_, _, fn_style, _) => + visit::FkItemFn(_, _, fn_style, _, _) => (true, fn_style == ast::Unsafety::Unsafe), - visit::FkMethod(_, sig) => + visit::FkMethod(_, sig, _) => (true, sig.unsafety == ast::Unsafety::Unsafe), _ => (false, false), }; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 2fa9c7c8fb..5235bbdf9c 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -99,6 +99,7 @@ pub enum LoanCause { ClosureCapture(Span), AddrOf, AutoRef, + AutoUnsafe, RefBinding, OverloadedOperator, ClosureInvocation, @@ -786,33 +787,19 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // process. fn walk_adjustment(&mut self, expr: &ast::Expr) { let typer = self.typer; - match typer.adjustments().borrow().get(&expr.id) { - None => { } - Some(adjustment) => { - match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { - // Creating a closure/fn-pointer consumes the - // input and stores it into the resulting - // rvalue. - debug!("walk_adjustment(AutoAddEnv|AdjustReifyFnPointer)"); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } - ty::AdjustDerefRef(ty::AutoDerefRef { - autoref: ref opt_autoref, - autoderefs: n - }) => { - self.walk_autoderefs(expr, n); - - match *opt_autoref { - None => { } - Some(ref r) => { - self.walk_autoref(expr, r, n); - } - } - } + if let Some(adjustment) = typer.adjustments().borrow().get(&expr.id) { + match *adjustment { + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer => { + // Creating a closure/fn-pointer or unsizing consumes + // the input and stores it into the resulting rvalue. + debug!("walk_adjustment(AdjustReifyFnPointer|AdjustUnsafeFnPointer)"); + let cmt_unadjusted = + return_if_err!(self.mc.cat_expr_unadjusted(expr)); + self.delegate_consume(expr.id, expr.span, cmt_unadjusted); + } + ty::AdjustDerefRef(ref adj) => { + self.walk_autoderefref(expr, adj); } } } @@ -827,7 +814,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs); for i in 0..autoderefs { - let deref_id = ty::MethodCall::autoderef(expr.id, i); + let deref_id = ty::MethodCall::autoderef(expr.id, i as u32); match self.typer.node_method_ty(deref_id) { None => {} Some(method_ty) => { @@ -852,39 +839,103 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } } + fn walk_autoderefref(&mut self, + expr: &ast::Expr, + adj: &ty::AutoDerefRef<'tcx>) { + debug!("walk_autoderefref expr={} adj={}", + expr.repr(self.tcx()), + adj.repr(self.tcx())); + + self.walk_autoderefs(expr, adj.autoderefs); + + let cmt_derefd = + return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); + + let cmt_refd = + self.walk_autoref(expr, cmt_derefd, adj.autoref); + + if adj.unsize.is_some() { + // Unsizing consumes the thin pointer and produces a fat one. + self.delegate_consume(expr.id, expr.span, cmt_refd); + } + } + + + /// Walks the autoref `opt_autoref` applied to the autoderef'd + /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` + /// after all relevant autoderefs have occurred. Because AutoRefs + /// can be recursive, this function is recursive: it first walks + /// deeply all the way down the autoref chain, and then processes + /// the autorefs on the way out. At each point, it returns the + /// `cmt` for the rvalue that will be produced by introduced an + /// autoref. fn walk_autoref(&mut self, expr: &ast::Expr, - autoref: &ty::AutoRef, - n: usize) { - debug!("walk_autoref expr={}", expr.repr(self.tcx())); + cmt_base: mc::cmt<'tcx>, + opt_autoref: Option>) + -> mc::cmt<'tcx> + { + debug!("walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})", + expr.id, + cmt_base.repr(self.tcx()), + opt_autoref); - match *autoref { - ty::AutoPtr(r, m, _) => { - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, n)); - debug!("walk_adjustment: cmt_derefd={}", - cmt_derefd.repr(self.tcx())); + let cmt_base_ty = cmt_base.ty; + + let autoref = match opt_autoref { + Some(ref autoref) => autoref, + None => { + // No AutoRef. + return cmt_base; + } + }; + + debug!("walk_autoref: expr.id={} cmt_base={}", + expr.id, + cmt_base.repr(self.tcx())); + match *autoref { + ty::AutoPtr(r, m) => { self.delegate.borrow(expr.id, expr.span, - cmt_derefd, - r, + cmt_base, + *r, ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsize(_) | - ty::AutoUnsizeUniq(_) => { - assert!(n == 1, format!("Expected exactly 1 deref with Uniq \ - AutoRefs, found: {}", n)); - let cmt_unadjusted = - return_if_err!(self.mc.cat_expr_unadjusted(expr)); - self.delegate_consume(expr.id, expr.span, cmt_unadjusted); - } - ty::AutoUnsafe(..) => { + + ty::AutoUnsafe(m) => { + debug!("walk_autoref: expr.id={} cmt_base={}", + expr.id, + cmt_base.repr(self.tcx())); + + // Converting from a &T to *T (or &mut T to *mut T) is + // treated as borrowing it for the enclosing temporary + // scope. + let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id)); + + self.delegate.borrow(expr.id, + expr.span, + cmt_base, + r, + ty::BorrowKind::from_mutbl(m), + AutoUnsafe); } } + + // Construct the categorization for the result of the autoref. + // This is always an rvalue, since we are producing a new + // (temporary) indirection. + + let adj_ty = + ty::adjust_ty_for_autoref(self.tcx(), + cmt_base_ty, + opt_autoref); + + self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) } + // When this returns true, it means that the expression *is* a // method-call (i.e. via the operator-overload). This true result // also implies that walk_overloaded_operator already took care of diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 36229a558e..3dbbcce27b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -373,8 +373,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::type_err<'tcx>) { + let span = trace.origin.span(); self.report_type_error(trace, terr); - ty::note_and_explain_type_err(self.tcx, terr); + ty::note_and_explain_type_err(self.tcx, terr, span); } /// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived @@ -812,7 +813,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } self.give_suggestion(same_regions); for &(ref trace, terr) in trace_origins { - self.report_type_error(trace.clone(), &terr); + self.report_and_explain_type_error(trace.clone(), &terr); } } @@ -965,7 +966,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { fn pick_lifetime(&self, region_names: &HashSet) -> (ast::Lifetime, FreshOrKept) { - if region_names.len() > 0 { + if !region_names.is_empty() { // It's not necessary to convert the set of region names to a // vector of string and then sort them. However, it makes the // choice of lifetime name deterministic and thus easier to test. @@ -1240,7 +1241,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { let lifetimes = path.segments.last().unwrap().parameters.lifetimes(); let mut insert = Vec::new(); - if lifetimes.len() == 0 { + if lifetimes.is_empty() { let anon = self.cur_anon.get(); for (i, a) in (anon..anon+expected).enumerate() { if anon_nums.contains(&a) { @@ -1360,7 +1361,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { ast::AngleBracketedParameters(ref data) => { let mut new_lts = Vec::new(); - if data.lifetimes.len() == 0 { + if data.lifetimes.is_empty() { // traverse once to see if there's a need to insert lifetime let need_insert = (0..expected).any(|i| { indexes.contains(&i) diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b11e25c059..0f62b440bf 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -987,7 +987,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_str)); if let Some(err) = err { - ty::note_and_explain_type_err(self.tcx, err) + ty::note_and_explain_type_err(self.tcx, err, sp) } } } diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 1fcbf80c90..054cec6874 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -88,7 +88,7 @@ pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, Err(_) => "/tmp/constraints.node%.dot".to_string(), }; - if output_template.len() == 0 { + if output_template.is_empty() { tcx.sess.bug("empty string provided as RUST_REGION_GRAPH"); } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index d41fdc5f09..c6be97e6db 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -246,7 +246,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } fn in_snapshot(&self) -> bool { - self.undo_log.borrow().len() > 0 + !self.undo_log.borrow().is_empty() } pub fn start_snapshot(&self) -> RegionSnapshot { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a08de58f90..c77a43e75c 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -36,7 +36,6 @@ use syntax::visit::Visitor; use syntax::visit; use std::iter::Enumerate; -use std::num::FromPrimitive; use std::slice; // The actual lang items defined come at the end of this file in one handy table. @@ -46,9 +45,12 @@ macro_rules! lets_do_this { $( $variant:ident, $name:expr, $method:ident; )* ) => { -#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq, Hash)] -pub enum LangItem { - $($variant),* + +enum_from_u32! { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] + pub enum LangItem { + $($variant,)* + } } pub struct LanguageItems { @@ -71,7 +73,7 @@ impl LanguageItems { } pub fn item_name(index: usize) -> &'static str { - let item: Option = FromPrimitive::from_usize(index); + let item: Option = LangItem::from_u32(index as u32); match item { $( Some($variant) => $name, )* None => "???" @@ -321,7 +323,6 @@ lets_do_this! { ExchangeHeapLangItem, "exchange_heap", exchange_heap; OwnedBoxLangItem, "owned_box", owned_box; - PhantomFnItem, "phantom_fn", phantom_fn; PhantomDataItem, "phantom_data", phantom_data; // Deprecated: diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d7161607b6..d4136637e5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -248,12 +248,12 @@ struct CaptureInfo { #[derive(Copy, Clone, Debug)] struct LocalInfo { id: NodeId, - ident: ast::Ident + name: ast::Name } #[derive(Copy, Clone, Debug)] enum VarKind { - Arg(NodeId, ast::Ident), + Arg(NodeId, ast::Name), Local(LocalInfo), ImplicitRet, CleanExit @@ -334,8 +334,8 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { fn variable_name(&self, var: Variable) -> String { match self.var_kinds[var.get()] { - Local(LocalInfo { ident: nm, .. }) | Arg(_, nm) => { - token::get_ident(nm).to_string() + Local(LocalInfo { name, .. }) | Arg(_, name) => { + token::get_name(name).to_string() }, ImplicitRet => "".to_string(), CleanExit => "".to_string() @@ -385,8 +385,8 @@ fn visit_fn(ir: &mut IrMaps, &*arg.pat, |_bm, arg_id, _x, path1| { debug!("adding argument {}", arg_id); - let ident = path1.node; - fn_maps.add_variable(Arg(arg_id, ident)); + let name = path1.node.name; + fn_maps.add_variable(Arg(arg_id, name)); }) }; @@ -418,11 +418,11 @@ fn visit_fn(ir: &mut IrMaps, fn visit_local(ir: &mut IrMaps, local: &ast::Local) { pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path1| { debug!("adding local variable {}", p_id); - let name = path1.node; + let name = path1.node.name; ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, - ident: name + name: name })); }); visit::walk_local(ir, local); @@ -433,11 +433,11 @@ fn visit_arm(ir: &mut IrMaps, arm: &ast::Arm) { pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| { debug!("adding local variable {} from match with bm {:?}", p_id, bm); - let name = path1.node; + let name = path1.node.name; ir.add_live_node_for_node(p_id, VarDefNode(sp)); ir.add_variable(Local(LocalInfo { id: p_id, - ident: name + name: name })); }) } @@ -716,7 +716,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { None => { // Vanilla 'break' or 'loop', so use the enclosing // loop scope - if self.loop_scope.len() == 0 { + if self.loop_scope.is_empty() { self.ir.tcx.sess.span_bug(sp, "break outside loop"); } else { *self.loop_scope.last().unwrap() @@ -1527,7 +1527,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // for nil return types, it is ok to not return a value expl. } else { let ends_with_stmt = match body.expr { - None if body.stmts.len() > 0 => + None if !body.stmts.is_empty() => match body.stmts.first().unwrap().node { ast::StmtSemi(ref e, _) => { ty::expr_ty(self.ir.tcx, &**e) == t_ret @@ -1586,7 +1586,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name.len() == 0 || name.as_bytes()[0] == ('_' as u8) { + if name.is_empty() || name.as_bytes()[0] == ('_' as u8) { None } else { Some(name) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 85255d04df..003306fe55 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -451,33 +451,23 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { Some(adjustment) => { match *adjustment { - ty::AdjustReifyFnPointer(..) | - ty::AdjustUnsafeFnPointer(..) => { - debug!("cat_expr(AdjustReifyFnPointer): {}", - expr.repr(self.tcx())); - // Convert a bare fn to a closure by adding NULL env. - // Result is an rvalue. - let expr_ty = try!(self.expr_ty_adjusted(expr)); - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) - } - ty::AdjustDerefRef( ty::AutoDerefRef { - autoref: Some(_), ..}) => { - debug!("cat_expr(AdjustDerefRef): {}", + autoref: None, unsize: None, autoderefs, ..}) => { + // Equivalent to *expr or something similar. + self.cat_expr_autoderefd(expr, autoderefs) + } + + ty::AdjustReifyFnPointer | + ty::AdjustUnsafeFnPointer | + ty::AdjustDerefRef(_) => { + debug!("cat_expr({}): {}", + adjustment.repr(self.tcx()), expr.repr(self.tcx())); - // Equivalent to &*expr or something similar. // Result is an rvalue. let expr_ty = try!(self.expr_ty_adjusted(expr)); Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) } - - ty::AdjustDerefRef( - ty::AutoDerefRef { - autoref: None, autoderefs}) => { - // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, autoderefs) - } } } } @@ -833,6 +823,15 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { ret } + /// Returns the lifetime of a temporary created by expr with id `id`. + /// This could be `'static` if `id` is part of a constant expression. + pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region { + match self.typer.temporary_scope(id) { + Some(scope) => ty::ReScope(scope), + None => ty::ReStatic + } + } + pub fn cat_rvalue_node(&self, id: ast::NodeId, span: Span, @@ -848,17 +847,12 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { _ => check_const::NOT_CONST }; + // Compute maximum lifetime of this rvalue. This is 'static if + // we can promote to a constant, otherwise equal to enclosing temp + // lifetime. let re = match qualif & check_const::NON_STATIC_BORROWS { - check_const::PURE_CONST => { - // Constant rvalues get promoted to 'static. - ty::ReStatic - } - _ => { - match self.typer.temporary_scope(id) { - Some(scope) => ty::ReScope(scope), - None => ty::ReStatic - } - } + check_const::PURE_CONST => ty::ReStatic, + _ => self.temporary_scope(id), }; let ret = self.cat_rvalue(id, span, re, expr_ty); debug!("cat_rvalue_node ret {}", ret.repr(self.tcx())); @@ -924,15 +918,9 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { deref_cnt: usize, deref_context: DerefKindContext) -> McResult> { - let adjustment = match self.typer.adjustments().borrow().get(&node.id()) { - Some(adj) if ty::adjust_is_object(adj) => ty::AutoObject, - _ if deref_cnt != 0 => ty::AutoDeref(deref_cnt), - _ => ty::NoAdjustment - }; - let method_call = ty::MethodCall { expr_id: node.id(), - adjustment: adjustment + autoderef: deref_cnt as u32 }; let method_ty = self.typer.node_method_ty(method_call); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 652f661325..2f7296051c 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -95,7 +95,15 @@ use syntax::visit::{Visitor, FnKind}; RustcDecodable, Debug, Copy)] pub enum CodeExtent { Misc(ast::NodeId), - DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id + + // extent of parameters passed to a function or closure (they + // outlive its body) + ParameterScope { fn_id: ast::NodeId, body_id: ast::NodeId }, + + // extent of destructors for temporaries of node-id + DestructionScope(ast::NodeId), + + // extent of code following a `let id = expr;` binding in a block Remainder(BlockRemainder) } @@ -153,15 +161,19 @@ impl CodeExtent { pub fn node_id(&self) -> ast::NodeId { match *self { CodeExtent::Misc(node_id) => node_id, + + // These cases all return rough approximations to the + // precise extent denoted by `self`. CodeExtent::Remainder(br) => br.block, CodeExtent::DestructionScope(node_id) => node_id, + CodeExtent::ParameterScope { fn_id: _, body_id } => body_id, } } /// Maps this scope to a potentially new one according to the /// NodeId transformer `f_id`. - pub fn map_id(&self, f_id: F) -> CodeExtent where - F: FnOnce(ast::NodeId) -> ast::NodeId, + pub fn map_id(&self, mut f_id: F) -> CodeExtent where + F: FnMut(ast::NodeId) -> ast::NodeId, { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), @@ -170,6 +182,8 @@ impl CodeExtent { block: f_id(br.block), first_statement_index: br.first_statement_index }), CodeExtent::DestructionScope(node_id) => CodeExtent::DestructionScope(f_id(node_id)), + CodeExtent::ParameterScope { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: f_id(fn_id), body_id: f_id(body_id) }, } } @@ -180,6 +194,7 @@ impl CodeExtent { match ast_map.find(self.node_id()) { Some(ast_map::NodeBlock(ref blk)) => { match *self { + CodeExtent::ParameterScope { .. } | CodeExtent::Misc(_) | CodeExtent::DestructionScope(_) => Some(blk.span), @@ -277,6 +292,7 @@ enum InnermostDeclaringBlock { Block(ast::NodeId), Statement(DeclaringStatementContext), Match(ast::NodeId), + FnDecl { fn_id: ast::NodeId, body_id: ast::NodeId }, } impl InnermostDeclaringBlock { @@ -285,6 +301,8 @@ impl InnermostDeclaringBlock { InnermostDeclaringBlock::None => { return Option::None; } + InnermostDeclaringBlock::FnDecl { fn_id, body_id } => + CodeExtent::ParameterScope { fn_id: fn_id, body_id: body_id }, InnermostDeclaringBlock::Block(id) | InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id), InnermostDeclaringBlock::Statement(s) => s.to_code_extent(), @@ -585,14 +603,11 @@ impl RegionMaps { self.sub_free_region(sub_fr, super_fr) } - (ty::ReEarlyBound(param_id_a, param_space_a, index_a, _), - ty::ReEarlyBound(param_id_b, param_space_b, index_b, _)) => { + (ty::ReEarlyBound(data_a), ty::ReEarlyBound(data_b)) => { // This case is used only to make sure that explicitly- // specified `Self` types match the real self type in - // implementations. - param_id_a == param_id_b && - param_space_a == param_space_b && - index_a == index_b + // implementations. Yuck. + data_a == data_b } _ => { @@ -1198,13 +1213,20 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); + // This scope covers the function body, which includes the + // bindings introduced by let statements as well as temporaries + // created by the fn's tail expression (if any). It does *not* + // include the fn parameters (see below). let body_scope = CodeExtent::from_node_id(body.id); visitor.region_maps.mark_as_terminating_scope(body_scope); let dtor_scope = CodeExtent::DestructionScope(body.id); visitor.region_maps.record_encl_scope(body_scope, dtor_scope); - record_superlifetime(visitor, dtor_scope, body.span); + let fn_decl_scope = CodeExtent::ParameterScope { fn_id: id, body_id: body.id }; + visitor.region_maps.record_encl_scope(dtor_scope, fn_decl_scope); + + record_superlifetime(visitor, fn_decl_scope, body.span); if let Some(root_id) = visitor.cx.root_id { visitor.region_maps.record_fn_parent(body.id, root_id); @@ -1212,11 +1234,13 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, let outer_cx = visitor.cx; - // The arguments and `self` are parented to the body of the fn. + // The arguments and `self` are parented to the fn. visitor.cx = Context { root_id: Some(body.id), - parent: InnermostEnclosingExpr::Some(body.id), - var_parent: InnermostDeclaringBlock::Block(body.id) + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::FnDecl { + fn_id: id, body_id: body.id + }, }; visit::walk_fn_decl(visitor, decl); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a3d71c989b..6f40e17855 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -24,6 +24,7 @@ use middle::region; use middle::subst; use middle::ty; use std::fmt; +use std::mem::replace; use syntax::ast; use syntax::codemap::Span; use syntax::parse::token::special_idents; @@ -70,6 +71,9 @@ struct LifetimeContext<'a> { // I'm sorry. trait_ref_hack: bool, + + // List of labels in the function/method currently under analysis. + labels_in_fn: Vec<(ast::Ident, Span)>, } enum ScopeChain<'a> { @@ -97,6 +101,7 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio scope: &ROOT_SCOPE, def_map: def_map, trait_ref_hack: false, + labels_in_fn: vec![], }, krate); sess.abort_if_errors(); named_region_map @@ -104,6 +109,10 @@ pub fn krate(sess: &Session, krate: &ast::Crate, def_map: &DefMap) -> NamedRegio impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_item(&mut self, item: &ast::Item) { + // Items save/restore the set of labels. This way innner items + // can freely reuse names, be they loop labels or lifetimes. + let saved = replace(&mut self.labels_in_fn, vec![]); + // Items always introduce a new root scope self.with(RootScope, |_, this| { match item.node { @@ -137,23 +146,26 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } } }); + + // Done traversing the item; restore saved set of labels. + replace(&mut self.labels_in_fn, saved); } fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, b: &'v ast::Block, s: Span, _: ast::NodeId) { match fk { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_early_late(subst::FnSpace, generics, |this| { - visit::walk_fn(this, fk, fd, b, s) + this.walk_fn(fk, fd, b, s) }) } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_early_late(subst::FnSpace, &sig.generics, |this| { - visit::walk_fn(this, fk, fd, b, s) + this.walk_fn(fk, fd, b, s) }) } visit::FkFnBlock(..) => { - visit::walk_fn(self, fk, fd, b, s) + self.walk_fn(fk, fd, b, s) } } } @@ -190,6 +202,10 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + // We reset the labels on every trait item, so that different + // methods in an impl can reuse label names. + let saved = replace(&mut self.labels_in_fn, vec![]); + if let ast::MethodTraitItem(ref sig, None) = trait_item.node { self.visit_early_late( subst::FnSpace, &sig.generics, @@ -197,6 +213,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } else { visit::walk_trait_item(self, trait_item); } + + replace(&mut self.labels_in_fn, saved); } fn visit_block(&mut self, b: &ast::Block) { @@ -227,7 +245,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ref bounds, ref bound_lifetimes, .. }) => { - if bound_lifetimes.len() > 0 { + if !bound_lifetimes.is_empty() { self.trait_ref_hack = true; let result = self.with(LateScope(bound_lifetimes, self.scope), |old_scope, this| { @@ -267,7 +285,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { _modifier: &ast::TraitBoundModifier) { debug!("visit_poly_trait_ref trait_ref={:?}", trait_ref); - if !self.trait_ref_hack || trait_ref.bound_lifetimes.len() > 0 { + if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { if self.trait_ref_hack { println!("{:?}", trait_ref.span); span_err!(self.sess, trait_ref.span, E0316, @@ -286,7 +304,170 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } } +#[derive(Copy, Clone, PartialEq)] +enum ShadowKind { Label, Lifetime } +struct Original { kind: ShadowKind, span: Span } +struct Shadower { kind: ShadowKind, span: Span } + +fn original_label(span: Span) -> Original { + Original { kind: ShadowKind::Label, span: span } +} +fn shadower_label(span: Span) -> Shadower { + Shadower { kind: ShadowKind::Label, span: span } +} +fn original_lifetime(l: &ast::Lifetime) -> Original { + Original { kind: ShadowKind::Lifetime, span: l.span } +} +fn shadower_lifetime(l: &ast::Lifetime) -> Shadower { + Shadower { kind: ShadowKind::Lifetime, span: l.span } +} + +impl ShadowKind { + fn desc(&self) -> &'static str { + match *self { + ShadowKind::Label => "label", + ShadowKind::Lifetime => "lifetime", + } + } +} + +fn signal_shadowing_problem( + sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) { + if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) { + // lifetime/lifetime shadowing is an error + sess.span_err(shadower.span, + &format!("{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), name, orig.kind.desc())); + } else { + // shadowing involving a label is only a warning, due to issues with + // labels and lifetimes not being macro-hygienic. + sess.span_warn(shadower.span, + &format!("{} name `{}` shadows a \ + {} name that is already in scope", + shadower.kind.desc(), name, orig.kind.desc())); + } + sess.span_note(orig.span, + &format!("shadowed {} `{}` declared here", + orig.kind.desc(), name)); +} + +// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning +// if one of the label shadows a lifetime or another label. +fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v ast::Block) { + + struct GatherLabels<'a> { + sess: &'a Session, + scope: Scope<'a>, + labels_in_fn: &'a mut Vec<(ast::Ident, Span)>, + } + + let mut gather = GatherLabels { + sess: ctxt.sess, + scope: ctxt.scope, + labels_in_fn: &mut ctxt.labels_in_fn, + }; + gather.visit_block(b); + return; + + impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { + fn visit_expr(&mut self, ex: &'v ast::Expr) { + if let Some(label) = expression_label(ex) { + for &(prior, prior_span) in &self.labels_in_fn[..] { + // FIXME (#24278): non-hygienic comparision + if label.name == prior.name { + signal_shadowing_problem(self.sess, + label.name, + original_label(prior_span), + shadower_label(ex.span)); + } + } + + check_if_label_shadows_lifetime(self.sess, + self.scope, + label, + ex.span); + + self.labels_in_fn.push((label, ex.span)); + } + visit::walk_expr(self, ex) + } + + fn visit_item(&mut self, _: &ast::Item) { + // do not recurse into items defined in the block + } + } + + fn expression_label(ex: &ast::Expr) -> Option { + match ex.node { + ast::ExprWhile(_, _, Some(label)) | + ast::ExprWhileLet(_, _, _, Some(label)) | + ast::ExprForLoop(_, _, _, Some(label)) | + ast::ExprLoop(_, Some(label)) => Some(label), + _ => None, + } + } + + fn check_if_label_shadows_lifetime<'a>(sess: &'a Session, + mut scope: Scope<'a>, + label: ast::Ident, + label_span: Span) { + loop { + match *scope { + BlockScope(_, s) => { scope = s; } + RootScope => { return; } + + EarlyScope(_, lifetimes, s) | + LateScope(lifetimes, s) => { + for lifetime_def in lifetimes { + // FIXME (#24278): non-hygienic comparision + if label.name == lifetime_def.lifetime.name { + signal_shadowing_problem( + sess, + label.name, + original_lifetime(&lifetime_def.lifetime), + shadower_label(label_span)); + return; + } + } + scope = s; + } + } + } + } +} + impl<'a> LifetimeContext<'a> { + // This is just like visit::walk_fn, except that it extracts the + // labels of the function body and swaps them in before visiting + // the function body itself. + fn walk_fn<'b>(&mut self, + fk: visit::FnKind, + fd: &ast::FnDecl, + fb: &'b ast::Block, + _span: Span) { + match fk { + visit::FkItemFn(_, generics, _, _, _) => { + visit::walk_fn_decl(self, fd); + self.visit_generics(generics); + } + visit::FkMethod(_, sig, _) => { + visit::walk_fn_decl(self, fd); + self.visit_generics(&sig.generics); + self.visit_explicit_self(&sig.explicit_self); + } + visit::FkFnBlock(..) => { + visit::walk_fn_decl(self, fd); + } + } + + // After inpsecting the decl, add all labels from the body to + // `self.labels_in_fn`. + extract_labels(self, fb); + + self.visit_block(fb); + } + fn with(&mut self, wrap_scope: ScopeChain, f: F) where F: FnOnce(Scope, &mut LifetimeContext), { @@ -297,6 +478,7 @@ impl<'a> LifetimeContext<'a> { scope: &wrap_scope, def_map: self.def_map, trait_ref_hack: self.trait_ref_hack, + labels_in_fn: self.labels_in_fn.clone(), }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); @@ -494,6 +676,17 @@ impl<'a> LifetimeContext<'a> { mut old_scope: Scope, lifetime: &ast::Lifetime) { + for &(label, label_span) in &self.labels_in_fn { + // FIXME (#24278): non-hygienic comparision + if lifetime.name == label.name { + signal_shadowing_problem(self.sess, + lifetime.name, + original_label(label_span), + shadower_lifetime(&lifetime)); + return; + } + } + loop { match *old_scope { BlockScope(_, s) => { @@ -507,19 +700,11 @@ impl<'a> LifetimeContext<'a> { EarlyScope(_, lifetimes, s) | LateScope(lifetimes, s) => { if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { - self.sess.span_warn( - lifetime.span, - &format!("lifetime name `{}` shadows another \ - lifetime name that is already in scope", - token::get_name(lifetime.name))); - self.sess.span_note( - lifetime_def.span, - &format!("shadowed lifetime `{}` declared here", - token::get_name(lifetime.name))); - self.sess.span_note( - lifetime.span, - "shadowed lifetimes are deprecated \ - and will become a hard error before 1.0"); + signal_shadowing_problem( + self.sess, + lifetime.name, + original_lifetime(&lifetime_def), + shadower_lifetime(&lifetime)); return; } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 7043b26136..d75dc861e8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -57,36 +57,50 @@ impl<'a> Annotator<'a> { attrs: &Vec, item_sp: Span, f: F, required: bool) where F: FnOnce(&mut Annotator), { - debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); - match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) { - Some(stab) => { - debug!("annotate: found {:?}", stab); - self.index.local.insert(id, stab.clone()); - - // Don't inherit #[stable(feature = "rust1", since = "1.0.0")] - if stab.level != attr::Stable { - let parent = replace(&mut self.parent, Some(stab)); - f(self); - self.parent = parent; - } else { + if self.index.staged_api { + debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); + match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) { + Some(stab) => { + debug!("annotate: found {:?}", stab); + self.index.local.insert(id, stab.clone()); + + // Don't inherit #[stable(feature = "rust1", since = "1.0.0")] + if stab.level != attr::Stable { + let parent = replace(&mut self.parent, Some(stab)); + f(self); + self.parent = parent; + } else { + f(self); + } + } + None => { + debug!("annotate: not found, use_parent = {:?}, parent = {:?}", + use_parent, self.parent); + if use_parent { + if let Some(stab) = self.parent.clone() { + self.index.local.insert(id, stab); + } else if self.index.staged_api && required + && self.export_map.contains(&id) + && !self.sess.opts.test { + self.sess.span_err(item_sp, + "This node does not have a stability attribute"); + } + } f(self); } } - None => { - debug!("annotate: not found, use_parent = {:?}, parent = {:?}", - use_parent, self.parent); - if use_parent { - if let Some(stab) = self.parent.clone() { - self.index.local.insert(id, stab); - } else if self.index.staged_api && required - && self.export_map.contains(&id) - && !self.sess.opts.test { - self.sess.span_err(item_sp, - "This node does not have a stability attribute"); - } + } else { + // Emit warnings for non-staged-api crates. These should be errors. + for attr in attrs { + let tag = attr.name(); + if tag == "unstable" || tag == "stable" || tag == "deprecated" { + attr::mark_used(attr); + self.sess.span_err(attr.span(), + "stability attributes may not be used outside \ + of the standard library"); } - f(self); } + f(self); } } } @@ -157,9 +171,6 @@ impl<'a, 'v> Visitor<'v> for Annotator<'a> { impl Index { /// Construct the stability index for a crate being compiled. pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) { - if !self.staged_api { - return; - } let mut annotator = Annotator { sess: sess, index: self, diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index e2ebe2bc0f..29f718fd09 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -361,7 +361,7 @@ impl VecPerParamSpace { pub fn get_self<'a>(&'a self) -> Option<&'a T> { let v = self.get_slice(SelfSpace); assert!(v.len() <= 1); - if v.len() == 0 { None } else { Some(&v[0]) } + if v.is_empty() { None } else { Some(&v[0]) } } pub fn len(&self, space: ParamSpace) -> usize { @@ -622,11 +622,11 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { // regions that appear in a function signature is done using // the specialized routine `ty::replace_late_regions()`. match r { - ty::ReEarlyBound(_, space, i, region_name) => { + ty::ReEarlyBound(data) => { match self.substs.regions { ErasedRegions => ty::ReStatic, NonerasedRegions(ref regions) => - match regions.opt_get(space, i as usize) { + match regions.opt_get(data.space, data.index as usize) { Some(&r) => { self.shift_region_through_binders(r) } @@ -635,11 +635,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { self.tcx().sess.span_bug( span, &format!("Type parameter out of range \ - when substituting in region {} (root type={}) \ - (space={:?}, index={})", - region_name.as_str(), - self.root_ty.repr(self.tcx()), - space, i)); + when substituting in region {} (root type={}) \ + (space={:?}, index={})", + data.name.as_str(), + self.root_ty.repr(self.tcx()), + data.space, + data.index)); } } } diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 2f2db8f38b..d21891ab23 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -26,7 +26,7 @@ use syntax::codemap::{DUMMY_SP, Span}; use util::ppaux::Repr; #[derive(Copy, Clone)] -struct ParamIsLocal(bool); +struct InferIsLocal(bool); /// True if there exist types that satisfy both of the two given impls. pub fn overlapping_impls(infcx: &InferCtxt, @@ -60,7 +60,7 @@ fn overlap(selcx: &mut SelectionContext, let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id, - util::free_substs_for_impl); + util::fresh_type_vars_for_impl); let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id, @@ -104,7 +104,7 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRe // if the orphan rules pass, that means that no ancestor crate can // impl this, so it's up to us. - if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() { + if orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(false)).is_ok() { debug!("trait_ref_is_knowable: orphan check passed"); return true; } @@ -126,7 +126,7 @@ pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRe // implemented by an upstream crate, which means that the impl // must be visible to us, and -- since the trait is fundamental // -- we can test. - orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err() + orphan_check_trait_ref(tcx, trait_ref, InferIsLocal(true)).is_err() } type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>, @@ -196,16 +196,16 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, return Ok(()); } - orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false)) + orphan_check_trait_ref(tcx, &trait_ref, InferIsLocal(false)) } fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>, - param_is_local: ParamIsLocal) + infer_is_local: InferIsLocal) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})", - trait_ref.repr(tcx), param_is_local.0); + debug!("orphan_check_trait_ref(trait_ref={}, infer_is_local={})", + trait_ref.repr(tcx), infer_is_local.0); // First, create an ordered iterator over all the type parameters to the trait, with the self // type appearing first. @@ -215,12 +215,12 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, // Find the first input type that either references a type parameter OR // some local type. for input_ty in input_tys { - if ty_is_local(tcx, input_ty, param_is_local) { + if ty_is_local(tcx, input_ty, infer_is_local) { debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx)); // First local input type. Check that there are no // uncovered type parameters. - let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local); + let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local); for uncovered_ty in uncovered_tys { if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); @@ -234,7 +234,7 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, // Otherwise, enforce invariant that there are no type // parameters reachable. - if !param_is_local.0 { + if !infer_is_local.0 { if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); return Err(OrphanCheckErr::UncoveredTy(param)); @@ -249,14 +249,14 @@ fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, - param_is_local: ParamIsLocal) + infer_is_local: InferIsLocal) -> Vec> { - if ty_is_local_constructor(tcx, ty, param_is_local) { + if ty_is_local_constructor(tcx, ty, infer_is_local) { vec![] } else if fundamental_ty(tcx, ty) { ty.walk_shallow() - .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter()) + .flat_map(|t| uncovered_tys(tcx, t, infer_is_local).into_iter()) .collect() } else { vec![ty] @@ -271,10 +271,10 @@ fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { } } -fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool +fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, infer_is_local: InferIsLocal) -> bool { - ty_is_local_constructor(tcx, ty, param_is_local) || - fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local)) + ty_is_local_constructor(tcx, ty, infer_is_local) || + fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, infer_is_local)) } fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool @@ -293,7 +293,7 @@ fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, - param_is_local: ParamIsLocal) + infer_is_local: InferIsLocal) -> bool { debug!("ty_is_local_constructor({})", ty.repr(tcx)); @@ -310,13 +310,13 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty::ty_ptr(..) | ty::ty_rptr(..) | ty::ty_tup(..) | - ty::ty_infer(..) | + ty::ty_param(..) | ty::ty_projection(..) => { false } - ty::ty_param(..) => { - param_is_local.0 + ty::ty_infer(..) => { + infer_is_local.0 } ty::ty_enum(def_id, _) | diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index ffd3299175..5938c6df92 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -298,7 +298,7 @@ impl<'tcx> FulfillmentContext<'tcx> { self.predicates.len(), errors.len()); - if errors.len() == 0 { + if errors.is_empty() { Ok(()) } else { Err(errors) diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index af6bb4cccc..a2ff86cd06 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -138,11 +138,10 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, match predicate { ty::Predicate::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - Some(data.def_id()) != tcx.lang_items.phantom_fn() && - data.0.trait_ref.substs.types.get_slice(TypeSpace) - .iter() - .cloned() - .any(is_self) + data.0.trait_ref.substs.types.get_slice(TypeSpace) + .iter() + .cloned() + .any(is_self) } ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) | diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index f7e7d071f8..ed8a6fb020 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -698,7 +698,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // is checked for in `evaluate_stack` (and hence users // who might care about this case, like coherence, should use // that function). - if candidates.len() == 0 { + if candidates.is_empty() { return Err(Unimplemented); } @@ -836,14 +836,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ambiguous: false }; - // Check for the `PhantomFn` trait. This is really just a - // special annotation that is *always* considered to match, no - // matter what the type parameters are etc. - if self.tcx().lang_items.phantom_fn() == Some(obligation.predicate.def_id()) { - candidates.vec.push(PhantomFnCandidate); - return Ok(candidates); - } - // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. @@ -881,7 +873,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { try!(self.assemble_candidates_from_caller_bounds(stack, &mut candidates)); // Default implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. - if candidates.vec.len() == 0 { + if candidates.vec.is_empty() { try!(self.assemble_candidates_from_default_impls(obligation, &mut candidates)); } debug!("candidate list size: {}", candidates.vec.len()); @@ -1386,6 +1378,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // #18453. true } + (&ImplCandidate(..), &ObjectCandidate(..)) => { + // This means that we are matching an object of type + // `Trait` against the trait `Trait`. In that case, we + // always prefer to use the object vtable over the + // impl. Like a where clause, the impl may or may not + // be the one that is used by the object (because the + // impl may have additional where-clauses that the + // object's source might not meet) -- if it is, using + // the vtable is fine. If it is not, using the vtable + // is good. A win win! + true + } (&DefaultImplCandidate(_), _) => { // Prefer other candidates over default implementations. self.tcx().sess.bug( diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 297cea1320..ddf941198e 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::region; use middle::subst::{Substs, VecPerParamSpace}; use middle::infer::InferCtxt; use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef}; @@ -304,34 +303,6 @@ pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, infcx.fresh_substs_for_generics(span, &impl_generics) } -// determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` -// would return ($0, $1) where $0 and $1 are freshly instantiated type -// variables. -pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - _span: Span, - impl_def_id: ast::DefId) - -> Substs<'tcx> -{ - let tcx = infcx.tcx; - let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; - - let some_types = impl_generics.types.map(|def| { - ty::mk_param_from_def(tcx, def) - }); - - let some_regions = impl_generics.regions.map(|def| { - // FIXME. This destruction scope information is pretty darn - // bogus; after all, the impl might not even be in this crate! - // But given what we do in coherence, it is harmless enough - // for now I think. -nmatsakis - let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID); - ty::free_region_from_def(extent, def) - }); - - Substs::new(some_types, some_regions) -} - impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VtableImpl({:?})", self.impl_def_id) @@ -506,7 +477,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>( def_id: fn_trait_def_id, substs: tcx.mk_substs(trait_substs), }); - ty::Binder((trait_ref, sig.0.output.unwrap())) + ty::Binder((trait_ref, sig.0.output.unwrap_or(ty::mk_nil(tcx)))) } impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1123c92363..d72004a930 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -20,7 +20,6 @@ pub use self::ClosureKind::*; pub use self::Variance::*; pub use self::AutoAdjustment::*; pub use self::Representability::*; -pub use self::UnsizeKind::*; pub use self::AutoRef::*; pub use self::ExprKind::*; pub use self::DtorKind::*; @@ -33,7 +32,6 @@ pub use self::ImplOrTraitItem::*; pub use self::BoundRegion::*; pub use self::sty::*; pub use self::IntVarValue::*; -pub use self::ExprAdjustment::*; pub use self::vtable_origin::*; pub use self::MethodOrigin::*; pub use self::CopyImplementationError::*; @@ -65,6 +63,7 @@ use util::ppaux::{Repr, UserString}; use util::common::{memoized, ErrorReported}; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::FnvHashMap; +use util::num::ToPrimitive; use arena::TypedArena; use std::borrow::{Borrow, Cow}; @@ -73,14 +72,13 @@ use std::cmp; use std::fmt; use std::hash::{Hash, SipHasher, Hasher}; use std::mem; -use std::num::ToPrimitive; use std::ops; use std::rc::Rc; use std::vec::IntoIter; use collections::enum_set::{EnumSet, CLike}; use std::collections::{HashMap, HashSet}; use syntax::abi; -use syntax::ast::{CrateNum, DefId, Ident, ItemTrait, LOCAL_CRATE}; +use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE}; use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId}; use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility}; use syntax::ast_util::{self, is_local, lit_is_str, local_def}; @@ -283,145 +281,97 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum AutoAdjustment<'tcx> { - AdjustReifyFnPointer(ast::DefId), // go from a fn-item type to a fn-pointer type - AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer - AdjustDerefRef(AutoDerefRef<'tcx>) -} - -#[derive(Clone, PartialEq, Debug)] -pub enum UnsizeKind<'tcx> { - // [T, ..n] -> [T], the usize field is n. - UnsizeLength(usize), - // An unsize coercion applied to the tail field of a struct. - // The usize is the index of the type parameter which is unsized. - UnsizeStruct(Box>, usize), - UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>), - UnsizeUpcast(Ty<'tcx>), + AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type + AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer + AdjustDerefRef(AutoDerefRef<'tcx>), } -#[derive(Clone, Debug)] +/// Represents coercing a pointer to a different kind of pointer - where 'kind' +/// here means either or both of raw vs borrowed vs unique and fat vs thin. +/// +/// We transform pointers by following the following steps in order: +/// 1. Deref the pointer `self.autoderefs` times (may be 0). +/// 2. If `autoref` is `Some(_)`, then take the address and produce either a +/// `&` or `*` pointer. +/// 3. If `unsize` is `Some(_)`, then apply the unsize transformation, +/// which will do things like convert thin pointers to fat +/// pointers, or convert structs containing thin pointers to +/// structs containing fat pointers, or convert between fat +/// pointers. We don't store the details of how the transform is +/// done (in fact, we don't know that, because it might depend on +/// the precise type parameters). We just store the target +/// type. Trans figures out what has to be done at monomorphization +/// time based on the precise source/target type at hand. +/// +/// To make that more concrete, here are some common scenarios: +/// +/// 1. The simplest cases are where the pointer is not adjusted fat vs thin. +/// Here the pointer will be dereferenced N times (where a dereference can +/// happen to to raw or borrowed pointers or any smart pointer which implements +/// Deref, including Box<_>). The number of dereferences is given by +/// `autoderefs`. It can then be auto-referenced zero or one times, indicated +/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is +/// None. +/// +/// 2. A thin-to-fat coercon involves unsizing the underlying data. We start +/// with a thin pointer, deref a number of times, unsize the underlying data, +/// then autoref. The 'unsize' phase may change a fixed length array to a +/// dynamically sized one, a concrete object to a trait object, or statically +/// sized struct to a dyncamically sized one. E.g., &[i32; 4] -> &[i32] is +/// represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 1, // &[i32; 4] -> [i32; 4] +/// autoref: Some(AutoPtr), // [i32] -> &[i32] +/// unsize: Some([i32]), // [i32; 4] -> [i32] +/// } +/// ``` +/// +/// Note that for a struct, the 'deep' unsizing of the struct is not recorded. +/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// The autoderef and -ref are the same as in the above example, but the type +/// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about +/// the underlying conversions from `[i32; 4]` to `[i32]`. +/// +/// 3. Coercing a `Box` to `Box` is an interesting special case. In +/// that case, we have the pointer we need coming in, so there are no +/// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. +/// At some point, of course, `Box` should move out of the compiler, in which +/// case this is analogous to transformating a struct. E.g., Box<[i32; 4]> -> +/// Box<[i32]> is represented by: +/// +/// ``` +/// AutoDerefRef { +/// autoderefs: 0, +/// autoref: None, +/// unsize: Some(Box<[i32]>), +/// } +/// ``` +#[derive(Copy, Clone, Debug)] pub struct AutoDerefRef<'tcx> { + /// Step 1. Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, - pub autoref: Option> -} -#[derive(Clone, PartialEq, Debug)] -pub enum AutoRef<'tcx> { - /// Convert from T to &T - /// The third field allows us to wrap other AutoRef adjustments. - AutoPtr(Region, ast::Mutability, Option>>), - - /// Convert [T, ..n] to [T] (or similar, depending on the kind) - AutoUnsize(UnsizeKind<'tcx>), - - /// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box. - /// With DST and Box a library type, this should be replaced by UnsizeStruct. - AutoUnsizeUniq(UnsizeKind<'tcx>), - - /// Convert from T to *T - /// Value to thin pointer - /// The second field allows us to wrap other AutoRef adjustments. - AutoUnsafe(ast::Mutability, Option>>), -} - -// Ugly little helper function. The first bool in the returned tuple is true if -// there is an 'unsize to trait object' adjustment at the bottom of the -// adjustment. If that is surrounded by an AutoPtr, then we also return the -// region of the AutoPtr (in the third argument). The second bool is true if the -// adjustment is unique. -fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { - fn unsize_kind_is_object(k: &UnsizeKind) -> bool { - match k { - &UnsizeVtable(..) => true, - &UnsizeStruct(box ref k, _) => unsize_kind_is_object(k), - _ => false - } - } + /// Step 2. Optionally produce a pointer/reference from the value. + pub autoref: Option>, - match autoref { - &AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None), - &AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None), - &AutoPtr(adj_r, _, Some(box ref autoref)) => { - let (b, u, r) = autoref_object_region(autoref); - if r.is_some() || u { - (b, u, r) - } else { - (b, u, Some(adj_r)) - } - } - &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref), - _ => (false, false, None) - } + /// Step 3. Unsize a pointer/reference value, e.g. `&[T; n]` to + /// `&[T]`. The stored type is the target pointer type. Note that + /// the source could be a thin or fat pointer. + pub unsize: Option>, } -// If the adjustment introduces a borrowed reference to a trait object, then -// returns the region of the borrowed reference. -pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, r) = autoref_object_region(autoref); - if b { - r - } else { - None - } - } - _ => None - } -} - -// Returns true if there is a trait cast at the bottom of the adjustment. -pub fn adjust_is_object(adj: &AutoAdjustment) -> bool { - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - let (b, _, _) = autoref_object_region(autoref); - b - } - _ => false - } -} - -// If possible, returns the type expected from the given adjustment. This is not -// possible if the adjustment depends on the type of the adjusted expression. -pub fn type_of_adjust<'tcx>(cx: &ctxt<'tcx>, adj: &AutoAdjustment<'tcx>) -> Option> { - fn type_of_autoref<'tcx>(cx: &ctxt<'tcx>, autoref: &AutoRef<'tcx>) -> Option> { - match autoref { - &AutoUnsize(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_trait(cx, principal.clone(), bounds.clone())) - } - _ => None - }, - &AutoUnsizeUniq(ref k) => match k { - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - Some(mk_uniq(cx, mk_trait(cx, principal.clone(), bounds.clone()))) - } - _ => None - }, - &AutoPtr(r, m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_rptr(cx, cx.mk_region(r), mt {mutbl: m, ty: ty})), - None => None - } - } - &AutoUnsafe(m, Some(box ref autoref)) => { - match type_of_autoref(cx, autoref) { - Some(ty) => Some(mk_ptr(cx, mt {mutbl: m, ty: ty})), - None => None - } - } - _ => None - } - } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AutoRef<'tcx> { + /// Convert from T to &T. + AutoPtr(&'tcx Region, ast::Mutability), - match adj { - &AdjustDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => { - type_of_autoref(cx, autoref) - } - _ => None - } + /// Convert from T to *T. + /// Value to thin pointer. + AutoUnsafe(ast::Mutability), } #[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)] @@ -509,35 +459,21 @@ pub struct MethodCallee<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct MethodCall { pub expr_id: ast::NodeId, - pub adjustment: ExprAdjustment -} - -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable, Copy)] -pub enum ExprAdjustment { - NoAdjustment, - AutoDeref(usize), - AutoObject + pub autoderef: u32 } impl MethodCall { pub fn expr(id: ast::NodeId) -> MethodCall { MethodCall { expr_id: id, - adjustment: NoAdjustment - } - } - - pub fn autoobject(id: ast::NodeId) -> MethodCall { - MethodCall { - expr_id: id, - adjustment: AutoObject + autoderef: 0 } } - pub fn autoderef(expr_id: ast::NodeId, autoderef: usize) -> MethodCall { + pub fn autoderef(expr_id: ast::NodeId, autoderef: u32) -> MethodCall { MethodCall { expr_id: expr_id, - adjustment: AutoDeref(1 + autoderef) + autoderef: 1 + autoderef } } } @@ -1092,6 +1028,13 @@ impl<'tcx> FnOutput<'tcx> { ty::FnDiverging => unreachable!() } } + + pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> { + match self { + ty::FnConverging(t) => t, + ty::FnDiverging => def + } + } } pub type PolyFnOutput<'tcx> = Binder>; @@ -1191,10 +1134,7 @@ pub enum Region { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type // parameters are substituted. - ReEarlyBound(/* param id */ ast::NodeId, - subst::ParamSpace, - /*index*/ u32, - ast::Name), + ReEarlyBound(EarlyBoundRegion), // Region bound in a function scope, which will be substituted when the // function is called. @@ -1226,6 +1166,14 @@ pub enum Region { ReEmpty, } +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] +pub struct EarlyBoundRegion { + pub param_id: ast::NodeId, + pub space: subst::ParamSpace, + pub index: u32, + pub name: ast::Name, +} + /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. @@ -1818,7 +1766,12 @@ pub struct RegionParameterDef { impl RegionParameterDef { pub fn to_early_bound_region(&self) -> ty::Region { - ty::ReEarlyBound(self.def_id.node, self.space, self.index, self.name) + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: self.def_id.node, + space: self.space, + index: self.index, + name: self.name, + }) } pub fn to_bound_region(&self) -> ty::BoundRegion { ty::BoundRegion::BrNamed(self.def_id, self.name) @@ -3093,7 +3046,7 @@ pub fn mk_trait<'tcx>(cx: &ctxt<'tcx>, } fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool { - bounds.len() == 0 || + bounds.is_empty() || bounds[1..].iter().enumerate().all( |(index, bound)| bounds[index].sort_key() <= bound.sort_key()) } @@ -3722,7 +3675,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { res = res | TC::OwnsDtor; } - if variants.len() != 0 { + if !variants.is_empty() { let repr_hints = lookup_repr_hints(cx, did); if repr_hints.len() > 1 { // this is an error later on, but this type isn't safe @@ -3744,7 +3697,7 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { if variants.len() == 2 { let mut data_idx = 0; - if variants[0].args.len() == 0 { + if variants[0].args.is_empty() { data_idx = 1; } @@ -4257,10 +4210,10 @@ pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool { match ty.sty { ty_enum(did, _) => { let variants = enum_variants(cx, did); - if variants.len() == 0 { + if variants.is_empty() { false } else { - variants.iter().all(|v| v.args.len() == 0) + variants.iter().all(|v| v.args.is_empty()) } } _ => false @@ -4361,8 +4314,8 @@ pub fn named_element_ty<'tcx>(cx: &ctxt<'tcx>, variant_info.arg_names.as_ref() .expect("must have struct enum variant if accessing a named fields") .iter().zip(variant_info.args.iter()) - .find(|&(ident, _)| ident.name == n) - .map(|(_ident, arg_t)| arg_t.subst(cx, substs)) + .find(|&(&name, _)| name == n) + .map(|(_name, arg_t)| arg_t.subst(cx, substs)) } _ => None } @@ -4574,16 +4527,15 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, return match adjustment { Some(adjustment) => { match *adjustment { - AdjustReifyFnPointer(_) => { + AdjustReifyFnPointer => { match unadjusted_ty.sty { ty::ty_bare_fn(Some(_), b) => { ty::mk_bare_fn(cx, None, b) } - ref b => { + _ => { cx.sess.bug( &format!("AdjustReifyFnPointer adjustment on non-fn-item: \ - {:?}", - b)); + {}", unadjusted_ty.repr(cx))); } } } @@ -4605,11 +4557,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, if !ty::type_is_error(adjusted_ty) { for i in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(expr_id, i); + let method_call = MethodCall::autoderef(expr_id, i as u32); match method_type(method_call) { Some(method_ty) => { - // overloaded deref operators have all late-bound - // regions fully instantiated and coverge + // Overloaded deref operators have all late-bound + // regions fully instantiated and coverge. let fn_ret = ty::no_late_bound_regions(cx, &ty_fn_ret(method_ty)).unwrap(); @@ -4622,8 +4574,7 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, None => { cx.sess.span_bug( span, - &format!("the {}th autoderef failed: \ - {}", + &format!("the {}th autoderef failed: {}", i, ty_to_string(cx, adjusted_ty)) ); @@ -4632,7 +4583,11 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } } - adjust_ty_for_autoref(cx, span, adjusted_ty, adj.autoref.as_ref()) + if let Some(target) = adj.unsize { + target + } else { + adjust_ty_for_autoref(cx, adjusted_ty, adj.autoref) + } } } } @@ -4641,73 +4596,16 @@ pub fn adjust_ty<'tcx, F>(cx: &ctxt<'tcx>, } pub fn adjust_ty_for_autoref<'tcx>(cx: &ctxt<'tcx>, - span: Span, ty: Ty<'tcx>, - autoref: Option<&AutoRef<'tcx>>) - -> Ty<'tcx> -{ + autoref: Option>) + -> Ty<'tcx> { match autoref { None => ty, - - Some(&AutoPtr(r, m, ref a)) => { - let adjusted_ty = match a { - &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)), - &None => ty - }; - mk_rptr(cx, cx.mk_region(r), mt { - ty: adjusted_ty, - mutbl: m - }) + Some(AutoPtr(r, m)) => { + mk_rptr(cx, r, mt { ty: ty, mutbl: m }) } - - Some(&AutoUnsafe(m, ref a)) => { - let adjusted_ty = match a { - &Some(box ref a) => adjust_ty_for_autoref(cx, span, ty, Some(a)), - &None => ty - }; - mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) - } - - Some(&AutoUnsize(ref k)) => unsize_ty(cx, ty, k, span), - - Some(&AutoUnsizeUniq(ref k)) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)), - } -} - -// Take a sized type and a sizing adjustment and produce an unsized version of -// the type. -pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>, - ty: Ty<'tcx>, - kind: &UnsizeKind<'tcx>, - span: Span) - -> Ty<'tcx> { - match kind { - &UnsizeLength(len) => match ty.sty { - ty_vec(ty, Some(n)) => { - assert!(len == n); - mk_vec(cx, ty, None) - } - _ => cx.sess.span_bug(span, - &format!("UnsizeLength with bad sty: {:?}", - ty_to_string(cx, ty))) - }, - &UnsizeStruct(box ref k, tp_index) => match ty.sty { - ty_struct(did, substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span); - let mut unsized_substs = substs.clone(); - unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty; - mk_struct(cx, did, cx.mk_substs(unsized_substs)) - } - _ => cx.sess.span_bug(span, - &format!("UnsizeStruct with bad sty: {:?}", - ty_to_string(cx, ty))) - }, - &UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => { - mk_trait(cx, principal.clone(), bounds.clone()) - } - &UnsizeUpcast(target_ty) => { - target_ty + Some(AutoUnsafe(m)) => { + mk_ptr(cx, mt { ty: ty, mutbl: m }) } } } @@ -4766,7 +4664,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { match resolve_expr(tcx, expr) { def::DefVariant(tid, vid, _) => { let variant_info = enum_variant_with_id(tcx, tid, vid); - if variant_info.args.len() > 0 { + if !variant_info.args.is_empty() { // N-ary variant. RvalueDatumExpr } else { @@ -5096,7 +4994,7 @@ pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String { } } -pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) { +pub fn note_and_explain_type_err<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>, sp: Span) { match *err { terr_regions_does_not_outlive(subregion, superregion) => { note_and_explain_region(cx, "", subregion, "..."); @@ -5127,6 +5025,16 @@ pub fn note_and_explain_type_err(cx: &ctxt, err: &type_err) { "expected concrete lifetime is ", conc_region, ""); } + terr_sorts(values) => { + let expected_str = ty_sort_string(cx, values.expected); + let found_str = ty_sort_string(cx, values.found); + if expected_str == found_str && expected_str == "closure" { + cx.sess.span_note(sp, &format!("no two closures, even if identical, have the same \ + type")); + cx.sess.span_help(sp, &format!("consider boxing your closure and/or \ + using it as a trait object")); + } + } _ => {} } } @@ -5341,7 +5249,7 @@ pub fn ty_to_def_id(ty: Ty) -> Option { #[derive(Clone)] pub struct VariantInfo<'tcx> { pub args: Vec>, - pub arg_names: Option>, + pub arg_names: Option>, pub ctor_ty: Option>, pub name: ast::Name, pub id: ast::DefId, @@ -5361,7 +5269,7 @@ impl<'tcx> VariantInfo<'tcx> { match ast_variant.node.kind { ast::TupleVariantKind(ref args) => { - let arg_tys = if args.len() > 0 { + let arg_tys = if !args.is_empty() { // the regions in the argument types come from the // enum def'n, and hence will all be early bound ty::no_late_bound_regions(cx, &ty_fn_args(ctor_ty)).unwrap() @@ -5382,13 +5290,13 @@ impl<'tcx> VariantInfo<'tcx> { ast::StructVariantKind(ref struct_def) => { let fields: &[StructField] = &struct_def.fields; - assert!(fields.len() > 0); + assert!(!fields.is_empty()); let arg_tys = struct_def.fields.iter() .map(|field| node_id_to_type(cx, field.node.id)).collect(); let arg_names = fields.iter().map(|field| { match field.node.kind { - NamedField(ident, _) => ident, + NamedField(ident, _) => ident.name, UnnamedField(..) => cx.sess.bug( "enum_variants: all fields in struct must have a name") } @@ -5954,6 +5862,47 @@ pub fn tup_fields<'tcx>(v: &[Ty<'tcx>]) -> Vec> { }).collect() } +/// Returns the deeply last field of nested structures, or the same type, +/// if not a structure at all. Corresponds to the only possible unsized +/// field, and its type can be used to determine unsizing strategy. +pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { + while let ty_struct(def_id, substs) = ty.sty { + match struct_fields(cx, def_id, substs).last() { + Some(f) => ty = f.mt.ty, + None => break + } + } + ty +} + +/// Same as applying struct_tail on `source` and `target`, but only +/// keeps going as long as the two types are instances of the same +/// structure definitions. +/// For `(Foo>, Foo)`, the result will be `(Foo, Trait)`, +/// whereas struct_tail produces `T`, and `Trait`, respectively. +pub fn struct_lockstep_tails<'tcx>(cx: &ctxt<'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>) + -> (Ty<'tcx>, Ty<'tcx>) { + let (mut a, mut b) = (source, target); + while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) { + if a_did != b_did { + continue; + } + if let Some(a_f) = struct_fields(cx, a_did, a_substs).last() { + if let Some(b_f) = struct_fields(cx, b_did, b_substs).last() { + a = a_f.mt.ty; + b = b_f.mt.ty; + } else { + break; + } + } else { + break; + } + } + (a, b) +} + #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { pub def: def::Def, @@ -6864,8 +6813,8 @@ pub fn with_freevars(tcx: &ty::ctxt, fid: ast::NodeId, f: F) -> T where impl<'tcx> AutoAdjustment<'tcx> { pub fn is_identity(&self) -> bool { match *self { - AdjustReifyFnPointer(..) => false, - AdjustUnsafeFnPointer(..) => false, + AdjustReifyFnPointer | + AdjustUnsafeFnPointer => false, AdjustDerefRef(ref r) => r.is_identity(), } } @@ -6873,7 +6822,7 @@ impl<'tcx> AutoAdjustment<'tcx> { impl<'tcx> AutoDerefRef<'tcx> { pub fn is_identity(&self) -> bool { - self.autoderefs == 0 && self.autoref.is_none() + self.autoderefs == 0 && self.unsize.is_none() && self.autoref.is_none() } } @@ -7034,8 +6983,8 @@ impl DebruijnIndex { impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AdjustReifyFnPointer(def_id) => { - format!("AdjustReifyFnPointer({})", def_id.repr(tcx)) + AdjustReifyFnPointer => { + format!("AdjustReifyFnPointer") } AdjustUnsafeFnPointer => { format!("AdjustUnsafeFnPointer") @@ -7047,37 +6996,21 @@ impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> { } } -impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> { - fn repr(&self, tcx: &ctxt<'tcx>) -> String { - match *self { - UnsizeLength(n) => format!("UnsizeLength({})", n), - UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n), - UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)), - UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)), - } - } -} - impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("AutoDerefRef({}, {})", self.autoderefs, self.autoref.repr(tcx)) + format!("AutoDerefRef({}, unsize={}, {})", + self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx)) } } impl<'tcx> Repr<'tcx> for AutoRef<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { match *self { - AutoPtr(a, b, ref c) => { - format!("AutoPtr({},{:?},{})", a.repr(tcx), b, c.repr(tcx)) - } - AutoUnsize(ref a) => { - format!("AutoUnsize({})", a.repr(tcx)) - } - AutoUnsizeUniq(ref a) => { - format!("AutoUnsizeUniq({})", a.repr(tcx)) + AutoPtr(a, b) => { + format!("AutoPtr({},{:?})", a.repr(tcx), b) } - AutoUnsafe(ref a, ref b) => { - format!("AutoUnsafe({:?},{})", a, b.repr(tcx)) + AutoUnsafe(ref a) => { + format!("AutoUnsafe({:?})", a) } } } @@ -7148,8 +7081,7 @@ pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, let meth_regions: Vec = method.generics.regions.get_slice(subst::FnSpace) .iter() - .map(|def| ty::ReEarlyBound(def.def_id.node, def.space, - def.index, def.name)) + .map(|def| def.to_early_bound_region()) .collect(); trait_ref.substs.clone().with_method(meth_tps, meth_regions) } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 5f77574f65..19a82e3f35 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -477,24 +477,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> { - fn fold_with>(&self, folder: &mut F) -> ty::UnsizeKind<'tcx> { - match *self { - ty::UnsizeLength(len) => ty::UnsizeLength(len), - ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n), - ty::UnsizeVtable(ty::TyTrait{ref principal, ref bounds}, self_ty) => { - ty::UnsizeVtable( - ty::TyTrait { - principal: principal.fold_with(folder), - bounds: bounds.fold_with(folder), - }, - self_ty.fold_with(folder)) - } - ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)), - } - } -} - impl<'tcx,O> TypeFoldable<'tcx> for traits::Obligation<'tcx,O> where O : TypeFoldable<'tcx> { @@ -768,16 +750,11 @@ pub fn super_fold_autoref<'tcx, T: TypeFolder<'tcx>>(this: &mut T, -> ty::AutoRef<'tcx> { match *autoref { - ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None), - ty::AutoPtr(r, m, Some(ref a)) => { - ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) - } - ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), - ty::AutoUnsafe(m, Some(ref a)) => { - ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a))) + ty::AutoPtr(r, m) => { + let r = r.fold_with(this); + ty::AutoPtr(this.tcx().mk_region(r), m) } - ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), - ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m) } } diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs index 1205b7d957..1c414d3d5f 100644 --- a/src/librustc/middle/ty_relate/mod.rs +++ b/src/librustc/middle/ty_relate/mod.rs @@ -122,11 +122,11 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, relate_substs(relation, opt_variances, a_subst, b_subst) } -fn relate_substs<'a,'tcx,R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, - a_subst: &Substs<'tcx>, - b_subst: &Substs<'tcx>) - -> RelateResult<'tcx, Substs<'tcx>> +fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> where R: TypeRelation<'a,'tcx> { let mut substs = Substs::empty(); @@ -161,11 +161,11 @@ fn relate_substs<'a,'tcx,R>(relation: &mut R, Ok(substs) } -fn relate_type_params<'a,'tcx,R>(relation: &mut R, - variances: Option<&[ty::Variance]>, - a_tys: &[Ty<'tcx>], - b_tys: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> +fn relate_type_params<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_tys: &[Ty<'tcx>], + b_tys: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> where R: TypeRelation<'a,'tcx> { if a_tys.len() != b_tys.len() { @@ -264,10 +264,10 @@ impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { } } -fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> RelateResult<'tcx, Vec>> +fn relate_arg_vecs<'a,'tcx:'a,R>(relation: &mut R, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> where R: TypeRelation<'a,'tcx> { if a_args.len() != b_args.len() { @@ -544,7 +544,7 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, .map(|(a, b)| relation.relate(a, b)) .collect::>()); Ok(ty::mk_tup(tcx, ts)) - } else if as_.len() != 0 && bs.len() != 0 { + } else if !(as_.is_empty() || bs.is_empty()) { Err(ty::terr_tuple_size( expected_found(relation, &as_.len(), &bs.len()))) } else { @@ -629,10 +629,10 @@ impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box /////////////////////////////////////////////////////////////////////////// // Error handling -pub fn expected_found<'a,'tcx,R,T>(relation: &mut R, - a: &T, - b: &T) - -> ty::expected_found +pub fn expected_found<'a,'tcx:'a,R,T>(relation: &mut R, + a: &T, + b: &T) + -> ty::expected_found where R: TypeRelation<'a,'tcx>, T: Clone { expected_found_bool(relation.a_is_expected(), a, b) diff --git a/src/librustc/plugin/mod.rs b/src/librustc/plugin/mod.rs index 3162c4fc57..4a85e1893f 100644 --- a/src/librustc/plugin/mod.rs +++ b/src/librustc/plugin/mod.rs @@ -47,7 +47,7 @@ //! #![plugin(myplugin)] //! ``` //! -//! See the [Plugins Chapter](../../book/plugins.html) of the book +//! See the [Plugins Chapter](../../book/compiler-plugins.html) of the book //! for more examples. pub use self::registry::Registry; diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index a73ed04ac0..322b5d3a8c 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -22,6 +22,7 @@ use syntax::ptr::P; use syntax::ast; use std::collections::HashMap; +use std::borrow::ToOwned; /// Structure used to register plugins. /// @@ -50,6 +51,9 @@ pub struct Registry<'a> { #[doc(hidden)] pub lint_groups: HashMap<&'static str, Vec>, + + #[doc(hidden)] + pub llvm_passes: Vec, } impl<'a> Registry<'a> { @@ -62,6 +66,7 @@ impl<'a> Registry<'a> { syntax_exts: vec!(), lint_passes: vec!(), lint_groups: HashMap::new(), + llvm_passes: vec!(), } } @@ -116,4 +121,13 @@ impl<'a> Registry<'a> { pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) { self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect()); } + + /// Register an LLVM pass. + /// + /// Registration with LLVM itself is handled through static C++ objects with + /// constructors. This method simply adds a name to the list of passes to + /// execute. + pub fn register_llvm_pass(&mut self, name: &str) { + self.llvm_passes.push(name.to_owned()); + } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a7d608d2c8..3fb6c191f6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -902,7 +902,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; output_types.sort(); output_types.dedup(); - if output_types.len() == 0 { + if output_types.is_empty() { output_types.push(OutputTypeExe); } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3e3e5e1796..500af5fc77 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -52,6 +52,7 @@ pub struct Session { pub working_dir: PathBuf, pub lint_store: RefCell, pub lints: RefCell>>, + pub plugin_llvm_passes: RefCell>, pub crate_types: RefCell>, pub crate_metadata: RefCell>, pub features: RefCell, @@ -68,13 +69,13 @@ impl Session { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); } - self.diagnostic().span_fatal(sp, msg) + panic!(self.diagnostic().span_fatal(sp, msg)) } pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); } - self.diagnostic().span_fatal_with_code(sp, msg, code) + panic!(self.diagnostic().span_fatal_with_code(sp, msg, code)) } pub fn fatal(&self, msg: &str) -> ! { if self.opts.treat_err_as_bug { @@ -142,6 +143,13 @@ impl Session { pub fn span_end_note(&self, sp: Span, msg: &str) { self.diagnostic().span_end_note(sp, msg) } + + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.diagnostic().span_suggestion(sp, msg, suggestion) + } pub fn span_help(&self, sp: Span, msg: &str) { self.diagnostic().span_help(sp, msg) } @@ -155,7 +163,7 @@ impl Session { self.diagnostic().handler().note(msg) } pub fn help(&self, msg: &str) { - self.diagnostic().handler().note(msg) + self.diagnostic().handler().help(msg) } pub fn opt_span_bug(&self, opt_sp: Option, msg: &str) -> ! { match opt_sp { @@ -391,6 +399,7 @@ pub fn build_session_(sopts: config::Options, working_dir: env::current_dir().unwrap(), lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(NodeMap()), + plugin_llvm_passes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), crate_metadata: RefCell::new(Vec::new()), features: RefCell::new(feature_gate::Features::new()), diff --git a/src/librustc/util/num.rs b/src/librustc/util/num.rs new file mode 100644 index 0000000000..da04976a96 --- /dev/null +++ b/src/librustc/util/num.rs @@ -0,0 +1,98 @@ +// 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. + +pub trait ToPrimitive { + fn to_i8(&self) -> Option; + fn to_i16(&self) -> Option; + fn to_i32(&self) -> Option; + fn to_i64(&self) -> Option; + fn to_u8(&self) -> Option; + fn to_u16(&self) -> Option; + fn to_u32(&self) -> Option; + fn to_u64(&self) -> Option; +} + +impl ToPrimitive for i64 { + fn to_i8(&self) -> Option { + if *self < i8::min_value() as i64 || *self > i8::max_value() as i64 { + None + } else { + Some(*self as i8) + } + } + fn to_i16(&self) -> Option { + if *self < i16::min_value() as i64 || *self > i16::max_value() as i64 { + None + } else { + Some(*self as i16) + } + } + fn to_i32(&self) -> Option { + if *self < i32::min_value() as i64 || *self > i32::max_value() as i64 { + None + } else { + Some(*self as i32) + } + } + fn to_i64(&self) -> Option { + Some(*self) + } + fn to_u8(&self) -> Option { + if *self < 0 || *self > u8::max_value() as i64 { + None + } else { + Some(*self as u8) + } + } + fn to_u16(&self) -> Option { + if *self < 0 || *self > u16::max_value() as i64 { + None + } else { + Some(*self as u16) + } + } + fn to_u32(&self) -> Option { + if *self < 0 || *self > u32::max_value() as i64 { + None + } else { + Some(*self as u32) + } + } + fn to_u64(&self) -> Option { + if *self < 0 {None} else {Some(*self as u64)} + } +} + +impl ToPrimitive for u64 { + fn to_i8(&self) -> Option { + if *self > i8::max_value() as u64 {None} else {Some(*self as i8)} + } + fn to_i16(&self) -> Option { + if *self > i16::max_value() as u64 {None} else {Some(*self as i16)} + } + fn to_i32(&self) -> Option { + if *self > i32::max_value() as u64 {None} else {Some(*self as i32)} + } + fn to_i64(&self) -> Option { + if *self > i64::max_value() as u64 {None} else {Some(*self as i64)} + } + fn to_u8(&self) -> Option { + if *self > u8::max_value() as u64 {None} else {Some(*self as u8)} + } + fn to_u16(&self) -> Option { + if *self > u16::max_value() as u64 {None} else {Some(*self as u16)} + } + fn to_u32(&self) -> Option { + if *self > u32::max_value() as u64 {None} else {Some(*self as u32)} + } + fn to_u64(&self) -> Option { + Some(*self) + } +} diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 60b422b376..6e0fe3e5a7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -113,6 +113,9 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) }; let scope_decorated_tag = match scope { region::CodeExtent::Misc(_) => tag, + region::CodeExtent::ParameterScope { .. } => { + "scope of parameters for function" + } region::CodeExtent::DestructionScope(_) => { new_string = format!("destruction scope surrounding {}", tag); &*new_string @@ -160,8 +163,8 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ReEmpty => { ("the empty lifetime".to_string(), None) } - ReEarlyBound(_, _, _, name) => { - (format!("{}", token::get_name(name)), None) + ReEarlyBound(ref data) => { + (format!("{}", token::get_name(data.name)), None) } // I believe these cases should not occur (except when debugging, @@ -220,8 +223,8 @@ pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> // `explain_region()` or `note_and_explain_region()`. match region { ty::ReScope(_) => prefix.to_string(), - ty::ReEarlyBound(_, _, _, name) => { - token::get_name(name).to_string() + ty::ReEarlyBound(ref data) => { + token::get_name(data.name).to_string() } ty::ReLateBound(_, br) => bound_region_to_string(cx, prefix, space, br), ty::ReFree(ref fr) => bound_region_to_string(cx, prefix, space, fr.bound_region), @@ -555,7 +558,7 @@ pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>, &strs[0][..] }, tail) - } else if strs.len() > 0 { + } else if !strs.is_empty() { format!("{}<{}>", base, strs.connect(", ")) } else { format!("{}", base) @@ -896,12 +899,12 @@ impl<'tcx> Repr<'tcx> for ty::BoundRegion { impl<'tcx> Repr<'tcx> for ty::Region { fn repr(&self, tcx: &ctxt) -> String { match *self { - ty::ReEarlyBound(id, space, index, name) => { + ty::ReEarlyBound(ref data) => { format!("ReEarlyBound({}, {:?}, {}, {})", - id, - space, - index, - token::get_name(name)) + data.param_id, + data.space, + data.index, + token::get_name(data.name)) } ty::ReLateBound(binder_id, ref bound_region) => { @@ -952,6 +955,8 @@ impl<'tcx> Repr<'tcx> for ty::FreeRegion { impl<'tcx> Repr<'tcx> for region::CodeExtent { fn repr(&self, _tcx: &ctxt) -> String { match *self { + region::CodeExtent::ParameterScope { fn_id, body_id } => + format!("ParameterScope({}, {})", fn_id, body_id), region::CodeExtent::Misc(node_id) => format!("Misc({})", node_id), region::CodeExtent::DestructionScope(node_id) => @@ -1264,7 +1269,7 @@ impl<'tcx, T> UserString<'tcx> for ty::Binder let names: Vec<_> = names.iter().map(|s| &s[..]).collect(); let value_str = unbound_value.user_string(tcx); - if names.len() == 0 { + if names.is_empty() { value_str } else { format!("for<{}> {}", names.connect(","), value_str) diff --git a/src/librustc_back/fs.rs b/src/librustc_back/fs.rs index 231f6ee3be..2ab4d7ff78 100644 --- a/src/librustc_back/fs.rs +++ b/src/librustc_back/fs.rs @@ -9,69 +9,42 @@ // except according to those terms. use std::io; -use std::env; -#[allow(deprecated)] use std::old_path::{self, GenericPath}; -#[allow(deprecated)] use std::old_io; use std::path::{Path, PathBuf}; -/// Returns an absolute path in the filesystem that `path` points to. The -/// returned path does not contain any symlinks in its hierarchy. -#[allow(deprecated)] // readlink is deprecated +#[cfg(windows)] pub fn realpath(original: &Path) -> io::Result { - let old = old_path::Path::new(original.to_str().unwrap()); - match old_realpath(&old) { - Ok(p) => Ok(PathBuf::from(p.as_str().unwrap())), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)) - } + Ok(original.to_path_buf()) } -#[allow(deprecated)] -fn old_realpath(original: &old_path::Path) -> old_io::IoResult { - use std::old_io::fs; - const MAX_LINKS_FOLLOWED: usize = 256; - let original = old_path::Path::new(env::current_dir().unwrap() - .to_str().unwrap()).join(original); +#[cfg(unix)] +pub fn realpath(original: &Path) -> io::Result { + use libc; + use std::ffi::{OsString, CString}; + use std::os::unix::prelude::*; - // Right now lstat on windows doesn't work quite well - if cfg!(windows) { - return Ok(original) + extern { + fn realpath(pathname: *const libc::c_char, resolved: *mut libc::c_char) + -> *mut libc::c_char; } - let result = original.root_path(); - let mut result = result.expect("make_absolute has no root_path"); - let mut followed = 0; - - for part in original.components() { - result.push(part); - - loop { - if followed == MAX_LINKS_FOLLOWED { - return Err(old_io::standard_error(old_io::InvalidInput)) - } - - match fs::lstat(&result) { - Err(..) => break, - Ok(ref stat) if stat.kind != old_io::FileType::Symlink => break, - Ok(..) => { - followed += 1; - let path = try!(fs::readlink(&result)); - result.pop(); - result.push(path); - } - } + let path = try!(CString::new(original.as_os_str().as_bytes())); + let mut buf = vec![0u8; 16 * 1024]; + unsafe { + let r = realpath(path.as_ptr(), buf.as_mut_ptr() as *mut _); + if r.is_null() { + return Err(io::Error::last_os_error()) } } - - return Ok(result); + let p = buf.iter().position(|i| *i == 0).unwrap(); + buf.truncate(p); + Ok(PathBuf::from(OsString::from_vec(buf))) } #[cfg(all(not(windows), test))] mod test { - use std::old_io; - use std::old_io::fs::{File, symlink, mkdir, mkdir_recursive}; - use super::old_realpath as realpath; - use std::old_io::TempDir; - use std::old_path::{Path, GenericPath}; + use tempdir::TempDir; + use std::fs::{self, File}; + use super::realpath; #[test] fn realpath_works() { @@ -83,15 +56,15 @@ mod test { let linkdir = tmpdir.join("test3"); File::create(&file).unwrap(); - mkdir(&dir, old_io::USER_RWX).unwrap(); - symlink(&file, &link).unwrap(); - symlink(&dir, &linkdir).unwrap(); - - assert!(realpath(&tmpdir).unwrap() == tmpdir); - assert!(realpath(&file).unwrap() == file); - assert!(realpath(&link).unwrap() == file); - assert!(realpath(&linkdir).unwrap() == dir); - assert!(realpath(&linkdir.join("link")).unwrap() == file); + fs::create_dir(&dir).unwrap(); + fs::soft_link(&file, &link).unwrap(); + fs::soft_link(&dir, &linkdir).unwrap(); + + assert_eq!(realpath(&tmpdir).unwrap(), tmpdir); + assert_eq!(realpath(&file).unwrap(), file); + assert_eq!(realpath(&link).unwrap(), file); + assert_eq!(realpath(&linkdir).unwrap(), dir); + assert_eq!(realpath(&linkdir.join("link")).unwrap(), file); } #[test] @@ -106,13 +79,13 @@ mod test { let e = d.join("e"); let f = a.join("f"); - mkdir_recursive(&b, old_io::USER_RWX).unwrap(); - mkdir_recursive(&d, old_io::USER_RWX).unwrap(); + fs::create_dir_all(&b).unwrap(); + fs::create_dir_all(&d).unwrap(); File::create(&f).unwrap(); - symlink(&Path::new("../d/e"), &c).unwrap(); - symlink(&Path::new("../f"), &e).unwrap(); + fs::soft_link("../d/e", &c).unwrap(); + fs::soft_link("../f", &e).unwrap(); - assert!(realpath(&c).unwrap() == f); - assert!(realpath(&e).unwrap() == f); + assert_eq!(realpath(&c).unwrap(), f); + assert_eq!(realpath(&e).unwrap(), f); } } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 7591ebf67f..3c54d6631f 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -35,17 +35,16 @@ #![feature(box_syntax)] #![feature(collections)] #![feature(core)] -#![feature(old_fs)] -#![feature(old_io)] -#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] #![feature(path_ext)] #![feature(step_by)] +#![feature(libc)] #![cfg_attr(test, feature(test, rand))] extern crate syntax; +extern crate libc; extern crate serialize; #[macro_use] extern crate log; diff --git a/src/librustc_back/rpath.rs b/src/librustc_back/rpath.rs index ff3f0b78f9..58073079d3 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_back/rpath.rs @@ -97,8 +97,9 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String let cwd = env::current_dir().unwrap(); let mut lib = (config.realpath)(&cwd.join(lib)).unwrap(); lib.pop(); - let mut output = (config.realpath)(&cwd.join(&config.out_filename)).unwrap(); + let mut output = cwd.join(&config.out_filename); output.pop(); + let output = (config.realpath)(&output).unwrap(); let relative = path_relative_from(&lib, &output) .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); // FIXME (#9639): This needs to handle non-utf8 paths diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index 898f20e745..9ed827da8b 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -12,10 +12,7 @@ //! use. This implementation is not intended for external use or for any use where security is //! important. -#![allow(deprecated)] // to_be32 - use std::iter::repeat; -use std::num::Int; use std::slice::bytes::{MutableByteVector, copy_memory}; use serialize::hex::ToHex; @@ -61,10 +58,10 @@ impl ToBits for u64 { /// Adds the specified number of bytes to the bit count. panic!() if this would cause numeric /// overflow. -fn add_bytes_to_bits(bits: T, bytes: T) -> T { +fn add_bytes_to_bits(bits: u64, bytes: u64) -> u64 { let (new_high_bits, new_low_bits) = bytes.to_bits(); - if new_high_bits > T::zero() { + if new_high_bits > 0 { panic!("numeric overflow occurred.") } @@ -543,14 +540,14 @@ mod tests { // A normal addition - no overflow occurs #[test] fn test_add_bytes_to_bits_ok() { - assert!(super::add_bytes_to_bits::(100, 10) == 180); + assert!(super::add_bytes_to_bits(100, 10) == 180); } // A simple failure case - adding 1 to the max value #[test] #[should_panic] fn test_add_bytes_to_bits_overflow() { - super::add_bytes_to_bits::(u64::MAX, 1); + super::add_bytes_to_bits(u64::MAX, 1); } struct Test { diff --git a/src/librustc_back/tempdir.rs b/src/librustc_back/tempdir.rs index b12732f879..de934cf65a 100644 --- a/src/librustc_back/tempdir.rs +++ b/src/librustc_back/tempdir.rs @@ -12,7 +12,7 @@ use std::env; use std::io::{self, Error, ErrorKind}; use std::fs; use std::path::{self, PathBuf, Path}; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; /// A wrapper for a path to temporary directory implementing automatic /// scope-based deletion. @@ -50,7 +50,7 @@ impl TempDir { let mut rng = thread_rng(); for _ in 0..NUM_RETRIES { let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect(); - let leaf = if prefix.len() > 0 { + let leaf = if !prefix.is_empty() { format!("{}.{}", prefix, suffix) } else { // If we're given an empty string for a prefix, then creating a diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index ce7b492c51..9776538de3 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -542,6 +542,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { euv::OverloadedOperator(..) | euv::AddrOf(..) | euv::AutoRef(..) | + euv::AutoUnsafe(..) | euv::ClosureInvocation(..) | euv::ForLoop(..) | euv::RefBinding(..) | diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index a13d1d1112..fa2ff43ecf 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -396,11 +396,11 @@ fn add_fragment_siblings_for_extension<'tcx>(this: &MoveData<'tcx>, match *origin_field_name { mc::NamedField(ast_name) => { let variant_arg_names = variant_info.arg_names.as_ref().unwrap(); - for variant_arg_ident in variant_arg_names { - if variant_arg_ident.name == ast_name { + for &variant_arg_name in variant_arg_names { + if variant_arg_name == ast_name { continue; } - let field_name = mc::NamedField(variant_arg_ident.name); + let field_name = mc::NamedField(variant_arg_name); add_fragment_sibling_local(field_name, Some(variant_info.id)); } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f8da075e4b..502321d075 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -24,6 +24,7 @@ use rustc::middle::cfg; use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; +use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::region; @@ -167,7 +168,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, all_loans.len()); for (loan_idx, loan) in all_loans.iter().enumerate() { loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx); - loan_dfcx.add_kill(loan.kill_scope.node_id(), loan_idx); + loan_dfcx.add_kill(KillFrom::ScopeEnd, loan.kill_scope.node_id(), loan_idx); } loan_dfcx.add_kills_from_flow_exits(cfg); loan_dfcx.propagate(cfg, body); @@ -522,6 +523,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } pub fn report(&self, err: BckError<'tcx>) { + // Catch and handle some particular cases. + match (&err.code, &err.cause) { + (&err_out_of_scope(ty::ReScope(_), ty::ReStatic), &euv::ClosureCapture(span)) | + (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..)), &euv::ClosureCapture(span)) => { + return self.report_out_of_scope_escaping_closure_capture(&err, span); + } + _ => { } + } + + // General fallback. self.span_err( err.span, &self.bckerr_to_string(&err)); @@ -775,6 +786,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { euv::AddrOf | euv::RefBinding | euv::AutoRef | + euv::AutoUnsafe | euv::ForLoop | euv::MatchDiscriminant => { format!("cannot borrow {} as mutable", descr) @@ -795,16 +807,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { format!("{} does not live long enough", msg) } err_borrowed_pointer_too_short(..) => { - let descr = match opt_loan_path(&err.cmt) { - Some(lp) => { - format!("`{}`", self.loan_path_to_string(&*lp)) - } - None => self.cmt_to_string(&*err.cmt), - }; - + let descr = self.cmt_to_path_or_string(&err.cmt); format!("lifetime of {} is too short to guarantee \ - its contents can be safely reborrowed", - descr) + its contents can be safely reborrowed", + descr) } } } @@ -822,6 +828,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::OverloadedOperator) | BorrowViolation(euv::AddrOf) | BorrowViolation(euv::AutoRef) | + BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::RefBinding) | BorrowViolation(euv::MatchDiscriminant) => { "cannot borrow data mutably" @@ -886,6 +893,39 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } + fn report_out_of_scope_escaping_closure_capture(&self, + err: &BckError<'tcx>, + capture_span: Span) + { + let cmt_path_or_string = self.cmt_to_path_or_string(&err.cmt); + + span_err!( + self.tcx.sess, err.span, E0373, + "closure may outlive the current function, \ + but it borrows {}, \ + which is owned by the current function", + cmt_path_or_string); + + self.tcx.sess.span_note( + capture_span, + &format!("{} is borrowed here", + cmt_path_or_string)); + + let suggestion = + match self.tcx.sess.codemap().span_to_snippet(err.span) { + Ok(string) => format!("move {}", string), + Err(_) => format!("move || ") + }; + + self.tcx.sess.span_suggestion( + err.span, + &format!("to force the closure to take ownership of {} \ + (and any other referenced variables), \ + use the `move` keyword, as shown:", + cmt_path_or_string), + suggestion); + } + pub fn note_and_explain_bckerr(&self, err: BckError<'tcx>) { let code = err.code; match code { @@ -1033,6 +1073,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn cmt_to_string(&self, cmt: &mc::cmt_<'tcx>) -> String { cmt.descriptive_string(self.tcx) } + + pub fn cmt_to_path_or_string(&self, cmt: &mc::cmt<'tcx>) -> String { + match opt_loan_path(cmt) { + Some(lp) => format!("`{}`", self.loan_path_to_string(&lp)), + None => self.cmt_to_string(cmt), + } + } } fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool { diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 2d1b57243d..1180717140 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -18,6 +18,7 @@ use rustc::middle::cfg; use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; +use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::ty; use rustc::util::nodemap::{FnvHashMap, NodeSet}; @@ -473,11 +474,13 @@ impl<'tcx> MoveData<'tcx> { for (i, assignment) in self.var_assignments.borrow().iter().enumerate() { dfcx_assign.add_gen(assignment.id, i); - self.kill_moves(assignment.path, assignment.id, dfcx_moves); + self.kill_moves(assignment.path, assignment.id, + KillFrom::Execution, dfcx_moves); } for assignment in &*self.path_assignments.borrow() { - self.kill_moves(assignment.path, assignment.id, dfcx_moves); + self.kill_moves(assignment.path, assignment.id, + KillFrom::Execution, dfcx_moves); } // Kill all moves related to a variable `x` when @@ -487,7 +490,8 @@ impl<'tcx> MoveData<'tcx> { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { let kill_scope = path.loan_path.kill_scope(tcx); let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); - self.kill_moves(path, kill_scope.node_id(), dfcx_moves); + self.kill_moves(path, kill_scope.node_id(), + KillFrom::ScopeEnd, dfcx_moves); } LpExtend(..) => {} } @@ -500,7 +504,9 @@ impl<'tcx> MoveData<'tcx> { match lp.kind { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { let kill_scope = lp.kill_scope(tcx); - dfcx_assign.add_kill(kill_scope.node_id(), assignment_index); + dfcx_assign.add_kill(KillFrom::ScopeEnd, + kill_scope.node_id(), + assignment_index); } LpExtend(..) => { tcx.sess.bug("var assignment for non var path"); @@ -568,6 +574,7 @@ impl<'tcx> MoveData<'tcx> { fn kill_moves(&self, path: MovePathIndex, kill_id: ast::NodeId, + kill_kind: KillFrom, dfcx_moves: &mut MoveDataFlow) { // We can only perform kills for paths that refer to a unique location, // since otherwise we may kill a move from one location with an @@ -576,7 +583,9 @@ impl<'tcx> MoveData<'tcx> { let loan_path = self.path_loan_path(path); if loan_path_is_precise(&*loan_path) { self.each_applicable_move(path, |move_index| { - dfcx_moves.add_kill(kill_id, move_index.get()); + debug!("kill_moves add_kill {:?} kill_id={} move_index={}", + kill_kind, kill_id, move_index.get()); + dfcx_moves.add_kill(kill_kind, kill_id, move_index.get()); true }); } diff --git a/src/libstd/sys/windows/udp.rs b/src/librustc_borrowck/diagnostics.rs similarity index 71% rename from src/libstd/sys/windows/udp.rs rename to src/librustc_borrowck/diagnostics.rs index 50f8fb828a..981b28593f 100644 --- a/src/libstd/sys/windows/udp.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -8,4 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use sys_common::net::UdpSocket; +#![allow(non_snake_case)] + +register_diagnostics! { + E0373 // closure may outlive current fn, but it borrows {}, which is owned by current fn +} + +__build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 54feed930a..647ea3555b 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -40,6 +40,10 @@ pub use borrowck::check_crate; pub use borrowck::build_borrowck_dataflow_data_for_fn; pub use borrowck::FnPartsWithCFG; +// NB: This module needs to be declared first so diagnostics are +// registered before they are used. +pub mod diagnostics; + mod borrowck; pub mod graphviz; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index fe05b48922..07fa997fe1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -395,6 +395,9 @@ pub fn phase_2_configure_and_expand(sess: &Session, // // baz! should not use this definition unless foo is enabled. + krate = time(time_passes, "configuration 1", krate, |krate| + syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); + time(time_passes, "gated macro checking", (), |_| { let features = syntax::feature_gate::check_crate_macros(sess.codemap(), @@ -406,8 +409,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, sess.abort_if_errors(); }); - krate = time(time_passes, "configuration 1", krate, |krate| - syntax::config::strip_unconfigured_items(sess.diagnostic(), krate)); krate = time(time_passes, "crate injection", krate, |krate| syntax::std_inject::maybe_inject_crates_ref(krate, @@ -438,7 +439,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } }); - let Registry { syntax_exts, lint_passes, lint_groups, .. } = registry; + let Registry { syntax_exts, lint_passes, lint_groups, llvm_passes, .. } = registry; { let mut ls = sess.lint_store.borrow_mut(); @@ -449,6 +450,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, for (name, to) in lint_groups { ls.register_group(Some(sess), true, name, to); } + + *sess.plugin_llvm_passes.borrow_mut() = llvm_passes; } // Lint plugins are registered; now we can process command line flags. @@ -885,9 +888,9 @@ pub fn collect_crate_types(session: &Session, // command line, then reuse the empty `base` Vec to hold the types that // will be found in crate attributes. let mut base = session.opts.crate_types.clone(); - if base.len() == 0 { + if base.is_empty() { base.extend(attr_types.into_iter()); - if base.len() == 0 { + if base.is_empty() { base.push(link::default_output_for_target(session)); } base.sort(); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index b32c6829a2..8f21a800d5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -277,7 +277,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { Some(ref code) => { match descriptions.find_description(&code[..]) { Some(ref description) => { - println!("{}", description); + // Slice off the leading newline and print. + print!("{}", &description[1..]); } None => { early_error(&format!("no extended information for {}", code)); @@ -424,7 +425,7 @@ impl RustcDefaultCalls { odir: &Option, ofile: &Option) -> Compilation { - if sess.opts.prints.len() == 0 { + if sess.opts.prints.is_empty() { return Compilation::Continue; } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 410f31e090..00c3450ebb 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -676,7 +676,7 @@ fn print_flowgraph(variants: Vec, }; match code { - _ if variants.len() == 0 => { + _ if variants.is_empty() => { let r = dot::render(&lcfg, &mut out); return expand_err_details(r); } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index f9be71561e..12b16e95a7 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -290,7 +290,12 @@ impl<'a, 'tcx> Env<'a, 'tcx> { -> ty::Region { let name = token::intern(name); - ty::ReEarlyBound(ast::DUMMY_NODE_ID, space, index, name) + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: ast::DUMMY_NODE_ID, + space: space, + index: index, + name: name + }) } pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3bb737ddc1..bdc3fdcfc1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -778,7 +778,7 @@ impl NonCamelCaseTypes { // start with a non-lowercase letter rather than non-uppercase // ones (some scripts don't have a concept of upper/lowercase) - ident.len() > 0 && !ident.char_at(0).is_lowercase() && !ident.contains('_') + !ident.is_empty() && !ident.char_at(0).is_lowercase() && !ident.contains('_') } fn to_camel_case(s: &str) -> String { @@ -957,7 +957,7 @@ impl LintPass for NonSnakeCase { fk: visit::FnKind, _: &ast::FnDecl, _: &ast::Block, span: Span, id: ast::NodeId) { match fk { - visit::FkMethod(ident, _) => match method_context(cx, id, span) { + visit::FkMethod(ident, _, _) => match method_context(cx, id, span) { MethodContext::PlainImpl => { self.check_snake_case(cx, "method", ident, span) }, @@ -966,7 +966,7 @@ impl LintPass for NonSnakeCase { }, _ => (), }, - visit::FkItemFn(ident, _, _, _) => { + visit::FkItemFn(ident, _, _, _, _) => { self.check_snake_case(cx, "function", ident, span) }, _ => (), @@ -1290,10 +1290,10 @@ impl LintPass for UnsafeCode { fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl, _: &ast::Block, span: Span, _: ast::NodeId) { match fk { - visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _) => + visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _) => cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"), - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { if sig.unsafety == ast::Unsafety::Unsafe { cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method") } @@ -1405,11 +1405,11 @@ impl LintPass for UnusedAllocation { if let Some(adjustment) = cx.tcx.adjustments.borrow().get(&e.id) { if let ty::AdjustDerefRef(ty::AutoDerefRef { ref autoref, .. }) = *adjustment { match autoref { - &Some(ty::AutoPtr(_, ast::MutImmutable, None)) => { + &Some(ty::AutoPtr(_, ast::MutImmutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use & instead"); } - &Some(ty::AutoPtr(_, ast::MutMutable, None)) => { + &Some(ty::AutoPtr(_, ast::MutMutable)) => { cx.span_lint(UNUSED_ALLOCATION, e.span, "unnecessary allocation, use &mut instead"); } @@ -1818,8 +1818,8 @@ impl LintPass for UnconditionalRecursion { ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; let (name, checker) = match fn_kind { - visit::FkItemFn(name, _, _, _) => (name, id_refers_to_this_fn as F), - visit::FkMethod(name, _) => (name, id_refers_to_this_method as F), + visit::FkItemFn(name, _, _, _, _) => (name, id_refers_to_this_fn as F), + visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F), // closures can't recur, so they don't matter. visit::FkFnBlock => return }; @@ -1900,7 +1900,7 @@ impl LintPass for UnconditionalRecursion { // doesn't return (e.g. calls a `-> !` function or `loop { /* // no break */ }`) shouldn't be linted unless it actually // recurs. - if !reached_exit_without_self_call && self_call_spans.len() > 0 { + if !reached_exit_without_self_call && !self_call_spans.is_empty() { cx.span_lint(UNCONDITIONAL_RECURSION, sp, "function cannot return without recurring"); diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 9b0ae2e9ef..7030ee5697 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -157,7 +157,7 @@ bitflags! { #[derive(Copy, Clone)] pub enum OtherAttribute { // The following are not really exposed in - // the LLVM c api so instead to add these + // the LLVM C api so instead to add these // we call a wrapper function in RustWrapper // that uses the C++ api. SanitizeAddressAttribute = 1 << 32, @@ -912,6 +912,7 @@ extern { AddressSpace: c_uint) -> ValueRef; pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef; pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; @@ -924,6 +925,7 @@ extern { pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); + pub fn LLVMGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; /* Operations on aliases */ pub fn LLVMAddAlias(M: ModuleRef, @@ -957,6 +959,7 @@ extern { pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); /* Operations on parameters */ pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 44ab096281..70c824a67a 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -686,7 +686,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { fn check_static_method(&mut self, span: Span, method_id: ast::DefId, - name: ast::Ident) { + name: ast::Name) { // If the method is a default method, we need to use the def_id of // the default implementation. let method_id = match ty::impl_or_trait_item(self.tcx, method_id) { @@ -696,7 +696,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { ty::TypeTraitItem(_) => method_id, }; - let string = token::get_ident(name); + let string = token::get_name(name); self.report_error(self.ensure_public(span, method_id, None, @@ -705,13 +705,13 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { } // Checks that a path is in scope. - fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Ident) { + fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Name) { debug!("privacy - path {}", self.nodestr(path_id)); let path_res = *self.tcx.def_map.borrow().get(&path_id).unwrap(); let ck = |tyname: &str| { let ck_public = |def: ast::DefId| { debug!("privacy - ck_public {:?}", def); - let name = token::get_ident(last); + let name = token::get_name(last); let origdid = path_res.def_id(); self.ensure_public(span, def, @@ -800,10 +800,10 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a method is in scope. fn check_method(&mut self, span: Span, origin: &MethodOrigin, - ident: ast::Ident) { + name: ast::Name) { match *origin { MethodStatic(method_id) => { - self.check_static_method(span, method_id, ident) + self.check_static_method(span, method_id, name) } MethodStaticClosure(_) => {} // Trait methods are always all public. The only controlling factor @@ -825,11 +825,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { match pid.node { ast::PathListIdent { id, name } => { debug!("privacy - ident item {}", id); - self.check_path(pid.span, id, name); + self.check_path(pid.span, id, name.name); } ast::PathListMod { id } => { debug!("privacy - mod item {}", id); - let name = prefix.segments.last().unwrap().identifier; + let name = prefix.segments.last().unwrap().identifier.name; self.check_path(pid.span, id, name); } } @@ -863,7 +863,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } Some(method) => { debug!("(privacy checking) checking impl method"); - self.check_method(expr.span, &method.origin, ident.node); + self.check_method(expr.span, &method.origin, ident.node.name); } } } @@ -1005,7 +1005,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) { - self.check_path(path.span, id, path.segments.last().unwrap().identifier); + self.check_path(path.span, id, path.segments.last().unwrap().identifier.name); visit::walk_path(self, path); } } @@ -1055,7 +1055,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { let check_inherited = |sp: Span, vis: ast::Visibility, note: &str| { if vis != ast::Inherited { tcx.sess.span_err(sp, "unnecessary visibility qualifier"); - if note.len() > 0 { + if !note.is_empty() { tcx.sess.span_note(sp, note); } } @@ -1178,7 +1178,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> { let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) { // `int` etc. (None doesn't seem to occur.) None | Some(def::DefPrimTy(..)) => return false, - Some(def) => def.def_id() + Some(def) => def.def_id(), }; // A path can only be private if: // it's in this crate... diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 52db6013f4..777154f3c9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -767,7 +767,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { f.name }).collect::>(); - if fields.len() == 0 { + if fields.is_empty() { child_name_bindings.define_value(def, DUMMY_SP, modifiers); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 045320e4fa..0058b31088 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -242,11 +242,11 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { _: Span, node_id: NodeId) { let rib_kind = match function_kind { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_generics(generics); ItemRibKind } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_generics(&sig.generics); self.visit_explicit_self(&sig.explicit_self); MethodRibKind @@ -1689,7 +1689,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } - DefTyParam(..) | DefSelfTy(_) => { + DefTyParam(..) | DefSelfTy(..) => { for rib in ribs { match rib.kind { NormalRibKind | MethodRibKind | ClosureRibKind(..) => { @@ -1797,63 +1797,57 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } ItemDefaultImpl(_, ref trait_ref) => { - self.with_optional_trait_ref(Some(trait_ref), |_| {}); + self.with_optional_trait_ref(Some(trait_ref), |_, _| {}); } - ItemImpl(_, _, + ItemImpl(_, + _, ref generics, - ref implemented_traits, + ref opt_trait_ref, ref self_type, ref impl_items) => { self.resolve_implementation(generics, - implemented_traits, + opt_trait_ref, &**self_type, + item.id, &impl_items[..]); } ItemTrait(_, ref generics, ref bounds, ref trait_items) => { self.check_if_primitive_type_name(name, item.span); - // Create a new rib for the self type. - let mut self_type_rib = Rib::new(ItemRibKind); - - // plain insert (no renaming, types are not currently hygienic....) - let name = special_names::type_self; - self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id))); - self.type_ribs.push(self_type_rib); - // Create a new rib for the trait-wide type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, TypeSpace, - NormalRibKind), + ItemRibKind), |this| { - this.visit_generics(generics); - visit::walk_ty_param_bounds_helper(this, bounds); - - for trait_item in trait_items { - // Create a new rib for the trait_item-specific type - // parameters. - // - // FIXME #4951: Do we need a node ID here? - - let type_parameters = match trait_item.node { - ast::MethodTraitItem(ref sig, _) => { - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind) - } - ast::TypeTraitItem(..) => { - this.check_if_primitive_type_name(trait_item.ident.name, - trait_item.span); - NoTypeParameters - } - }; - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_trait_item(this, trait_item) - }); - } + this.with_self_rib(DefSelfTy(Some(local_def(item.id)), None), |this| { + this.visit_generics(generics); + visit::walk_ty_param_bounds_helper(this, bounds); + + for trait_item in trait_items { + // Create a new rib for the trait_item-specific type + // parameters. + // + // FIXME #4951: Do we need a node ID here? + + let type_parameters = match trait_item.node { + ast::MethodTraitItem(ref sig, _) => { + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind) + } + ast::TypeTraitItem(..) => { + this.check_if_primitive_type_name(trait_item.ident.name, + trait_item.span); + NoTypeParameters + } + }; + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_trait_item(this, trait_item) + }); + } + }); }); - - self.type_ribs.pop(); } ItemMod(_) | ItemForeignMod(_) => { @@ -2030,8 +2024,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { visit::walk_generics(self, generics); } - fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T where - F: FnOnce(&mut Resolver) -> T, + fn with_current_self_type(&mut self, self_type: &Ty, f: F) -> T + where F: FnOnce(&mut Resolver) -> T { // Handle nested impls (inside fn bodies) let previous_value = replace(&mut self.current_self_type, Some(self_type.clone())); @@ -2044,29 +2038,44 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { opt_trait_ref: Option<&TraitRef>, f: F) -> T - where F: FnOnce(&mut Resolver) -> T, + where F: FnOnce(&mut Resolver, Option) -> T { let mut new_val = None; + let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - match self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, 0) { - Ok(path_res) => { - self.record_def(trait_ref.ref_id, path_res); - new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); - } - Err(_) => { /* error was already reported */ } + if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id, + &trait_ref.path, 0) { + assert!(path_res.depth == 0); + self.record_def(trait_ref.ref_id, path_res); + new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); + new_id = Some(path_res.base_def.def_id()); } visit::walk_trait_ref(self, trait_ref); } let original_trait_ref = replace(&mut self.current_trait_ref, new_val); - let result = f(self); + let result = f(self, new_id); self.current_trait_ref = original_trait_ref; result } + fn with_self_rib(&mut self, self_def: Def, f: F) + where F: FnOnce(&mut Resolver) + { + let mut self_type_rib = Rib::new(NormalRibKind); + + // plain insert (no renaming, types are not currently hygienic....) + let name = special_names::type_self; + self_type_rib.bindings.insert(name, DlDef(self_def)); + self.type_ribs.push(self_type_rib); + f(self); + self.type_ribs.pop(); + } + fn resolve_implementation(&mut self, generics: &Generics, opt_trait_reference: &Option, self_type: &Ty, + item_id: NodeId, impl_items: &[P]) { // If applicable, create a rib for the type parameters. self.with_type_parameter_rib(HasTypeParameters(generics, @@ -2077,40 +2086,42 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { this.visit_generics(generics); // Resolve the trait reference, if necessary. - this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this| { + this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { // Resolve the self type. this.visit_ty(self_type); - this.with_current_self_type(self_type, |this| { - for impl_item in impl_items { - match impl_item.node { - MethodImplItem(ref sig, _) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); - - // We also need a new scope for the method- - // specific type parameters. - let type_parameters = - HasTypeParameters(&sig.generics, - FnSpace, - MethodRibKind); - this.with_type_parameter_rib(type_parameters, |this| { - visit::walk_impl_item(this, impl_item); - }); - } - TypeImplItem(ref ty) => { - // If this is a trait impl, ensure the method - // exists in trait - this.check_trait_item(impl_item.ident.name, - impl_item.span); + this.with_self_rib(DefSelfTy(trait_id, Some((item_id, self_type.id))), |this| { + this.with_current_self_type(self_type, |this| { + for impl_item in impl_items { + match impl_item.node { + MethodImplItem(ref sig, _) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); + + // We also need a new scope for the method- + // specific type parameters. + let type_parameters = + HasTypeParameters(&sig.generics, + FnSpace, + MethodRibKind); + this.with_type_parameter_rib(type_parameters, |this| { + visit::walk_impl_item(this, impl_item); + }); + } + TypeImplItem(ref ty) => { + // If this is a trait impl, ensure the method + // exists in trait + this.check_trait_item(impl_item.ident.name, + impl_item.span); - this.visit_ty(ty); + this.visit_ty(ty); + } + ast::MacImplItem(_) => {} } - ast::MacImplItem(_) => {} } - } + }); }); }); }); @@ -2161,7 +2172,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // check that all of the arms in an or-pattern have exactly the // same set of bindings, with the same binding modes for each. fn check_consistent_bindings(&mut self, arm: &Arm) { - if arm.pats.len() == 0 { + if arm.pats.is_empty() { return } let map_0 = self.binding_mode_map(&*arm.pats[0]); @@ -3061,7 +3072,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - if values.len() > 0 && + if !values.is_empty() && values[smallest] != usize::MAX && values[smallest] < name.len() + 2 && values[smallest] <= max_distance && @@ -3217,7 +3228,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { format!("to call `{}::{}`", path_str, path_name) }; - if msg.len() > 0 { + if !msg.is_empty() { msg = format!(". Did you mean {}?", msg) } @@ -3511,7 +3522,7 @@ fn module_to_string(module: &Module) -> String { } collect_mod(&mut names, module); - if names.len() == 0 { + if names.is_empty() { return "???".to_string(); } names_to_string(&names.into_iter().rev().collect::>()) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f1a8507b17..4b488981bf 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -304,7 +304,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { module_to_string(&*module_)); // First, resolve the module path for the directive, if necessary. - let container = if module_path.len() == 0 { + let container = if module_path.is_empty() { // Use the crate root. Some((self.resolver.graph_root.get_module(), LastMod(AllPublic))) } else { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index ad77735189..b53be98a06 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -269,7 +269,7 @@ pub fn sanitize(s: &str) -> String { } // Underscore-qualify anything that didn't start as an ident. - if result.len() > 0 && + if !result.is_empty() && result.as_bytes()[0] != '_' as u8 && ! (result.as_bytes()[0] as char).is_xid_start() { return format!("_{}", &result[..]); @@ -463,7 +463,7 @@ pub fn filename_for_input(sess: &Session, } config::CrateTypeExecutable => { let suffix = &sess.target.target.options.exe_suffix; - if suffix.len() == 0 { + if suffix.is_empty() { out_filename.to_path_buf() } else { out_filename.with_extension(&suffix[1..]) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 4e099a4ca8..e8752ab14b 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -21,9 +21,6 @@ use libc; use flate; use std::ffi::CString; -use std::mem; -#[allow(deprecated)] -use std::num::Int; pub fn run(sess: &session::Session, llmod: ModuleRef, tm: TargetMachineRef, reachable: &[String]) { @@ -198,19 +195,15 @@ fn is_versioned_bytecode_format(bc: &[u8]) -> bool { } fn extract_bytecode_format_version(bc: &[u8]) -> u32 { - return read_from_le_bytes::(bc, link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET); + let pos = link::RLIB_BYTECODE_OBJECT_VERSION_OFFSET; + let byte_data = &bc[pos..pos + 4]; + let data = unsafe { *(byte_data.as_ptr() as *const u32) }; + u32::from_le(data) } fn extract_compressed_bytecode_size_v1(bc: &[u8]) -> u64 { - return read_from_le_bytes::(bc, link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET); -} - -#[allow(deprecated)] -fn read_from_le_bytes(bytes: &[u8], position_in_bytes: usize) -> T { - let byte_data = &bytes[position_in_bytes..position_in_bytes + mem::size_of::()]; - let data = unsafe { - *(byte_data.as_ptr() as *const T) - }; - - Int::from_le(data) + let pos = link::RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET; + let byte_data = &bc[pos..pos + 8]; + let data = unsafe { *(byte_data.as_ptr() as *const u64) }; + u64::from_le(data) } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index cc588a365f..de21d62651 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -319,6 +319,8 @@ struct CodegenContext<'a> { lto_ctxt: Option<(&'a Session, &'a [String])>, // Handler to use for diagnostics produced during codegen. handler: &'a Handler, + // LLVM passes added by plugins. + plugin_passes: Vec, // LLVM optimizations for which we want to print remarks. remark: Passes, } @@ -328,6 +330,7 @@ impl<'a> CodegenContext<'a> { CodegenContext { lto_ctxt: Some((sess, reachable)), handler: sess.diagnostic().handler(), + plugin_passes: sess.plugin_llvm_passes.borrow().clone(), remark: sess.opts.cg.remark.clone(), } } @@ -461,6 +464,16 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + for pass in &cgcx.plugin_passes { + let pass = CString::new(pass.clone()).unwrap(); + if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { + cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \ + does not recognize it", pass)); + } + } + + cgcx.handler.abort_if_errors(); + // Finally, run the actual optimization passes time(config.time_passes, "llvm function passes", (), |()| llvm::LLVMRustRunFunctionPassManager(fpm, llmod)); @@ -907,6 +920,7 @@ fn run_work_multithreaded(sess: &Session, for i in 0..num_workers { let work_items_arc = work_items_arc.clone(); let diag_emitter = diag_emitter.clone(); + let plugin_passes = sess.plugin_llvm_passes.borrow().clone(); let remark = sess.opts.cg.remark.clone(); let (tx, rx) = channel(); @@ -921,6 +935,7 @@ fn run_work_multithreaded(sess: &Session, let cgcx = CodegenContext { lto_ctxt: None, handler: &diag_handler, + plugin_passes: plugin_passes, remark: remark, }; diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 26fcf947e4..57dba30723 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -248,7 +248,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefFn(..) => Some(recorder::FnRef), - def::DefSelfTy(_) | + def::DefSelfTy(..) | def::DefRegion(_) | def::DefLabel(_) | def::DefTyParam(..) | @@ -263,7 +263,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { fn process_formals(&mut self, formals: &Vec, qualname: &str) { for arg in formals { - assert!(self.collected_paths.len() == 0 && !self.collecting); + assert!(self.collected_paths.is_empty() && !self.collecting); self.collecting = true; self.visit_pat(&*arg.pat); self.collecting = false; @@ -288,7 +288,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { fn process_method(&mut self, sig: &ast::MethodSig, body: Option<&ast::Block>, - id: ast::NodeId, ident: ast::Ident, + id: ast::NodeId, name: ast::Name, span: Span) { if generated_code(span) { return; @@ -354,7 +354,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }, }; - let qualname = &format!("{}::{}", qualname, &get_ident(ident)); + let qualname = &format!("{}::{}", qualname, &token::get_name(name)); // record the decl for this def (if it has one) let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx, @@ -1119,7 +1119,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { let glob_map = glob_map.as_ref().unwrap(); if glob_map.contains_key(&item.id) { for n in glob_map.get(&item.id).unwrap() { - if name_string.len() > 0 { + if !name_string.is_empty() { name_string.push_str(", "); } name_string.push_str(n.as_str()); @@ -1238,7 +1238,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { match trait_item.node { ast::MethodTraitItem(ref sig, ref body) => { self.process_method(sig, body.as_ref().map(|x| &**x), - trait_item.id, trait_item.ident, trait_item.span); + trait_item.id, trait_item.ident.name, trait_item.span); } ast::TypeTraitItem(..) => {} } @@ -1248,7 +1248,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { match impl_item.node { ast::MethodImplItem(ref sig, ref body) => { self.process_method(sig, Some(body), impl_item.id, - impl_item.ident, impl_item.span); + impl_item.ident.name, impl_item.span); } ast::TypeImplItem(_) | ast::MacImplItem(_) => {} @@ -1394,7 +1394,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { } fn visit_arm(&mut self, arm: &ast::Arm) { - assert!(self.collected_paths.len() == 0 && !self.collecting); + assert!(self.collected_paths.is_empty() && !self.collecting); self.collecting = true; for pattern in &arm.pats { // collect paths from the arm's patterns @@ -1462,7 +1462,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { // The local could declare multiple new vars, we must walk the // pattern and collect them all. - assert!(self.collected_paths.len() == 0 && !self.collecting); + assert!(self.collected_paths.is_empty() && !self.collecting); self.collecting = true; self.visit_pat(&*l.pat); self.collecting = false; diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index ef599a01e7..744ec5a616 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -220,10 +220,9 @@ use util::ppaux::{Repr, vec_map_to_string}; use std; use std::cmp::Ordering; -use std::iter::AdditiveIterator; use std::rc::Rc; use syntax::ast; -use syntax::ast::{DUMMY_NODE_ID, Ident, NodeId}; +use syntax::ast::{DUMMY_NODE_ID, NodeId}; use syntax::codemap::Span; use syntax::fold::Folder; use syntax::ptr::P; @@ -349,7 +348,7 @@ pub struct BindingInfo<'tcx> { pub ty: Ty<'tcx>, } -type BindingsMap<'tcx> = FnvHashMap>; +type BindingsMap<'tcx> = FnvHashMap>; struct ArmData<'p, 'blk, 'tcx: 'blk> { bodycx: Block<'blk, 'tcx>, @@ -364,7 +363,7 @@ struct ArmData<'p, 'blk, 'tcx: 'blk> { struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> { pats: Vec<&'p ast::Pat>, data: &'a ArmData<'p, 'blk, 'tcx>, - bound_ptrs: Vec<(Ident, ValueRef)>, + bound_ptrs: Vec<(ast::Ident, ValueRef)>, // Thread along renamings done by the check_match::StaticInliner, so we can // map back to original NodeIds pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>> @@ -923,7 +922,7 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval)); bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum); - debuginfo::create_match_binding_metadata(bcx, ident, binding_info); + debuginfo::create_match_binding_metadata(bcx, ident.name, binding_info); } bcx } @@ -989,7 +988,7 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _indenter = indenter(); let _icx = push_ctxt("match::compile_submatch"); let mut bcx = bcx; - if m.len() == 0 { + if m.is_empty() { if chk.is_fallible() { chk.handle_fail(bcx); } @@ -1113,7 +1112,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let mut kind = NoBranch; let mut test_val = val; debug!("test_val={}", bcx.val_to_string(test_val)); - if opts.len() > 0 { + if !opts.is_empty() { match opts[0] { ConstantValue(..) | ConstantRange(..) => { test_val = load_if_immediate(bcx, val, left_ty); @@ -1153,7 +1152,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }; let defaults = enter_default(else_cx, dm, m, col, val); - let exhaustive = chk.is_infallible() && defaults.len() == 0; + let exhaustive = chk.is_infallible() && defaults.is_empty(); let len = opts.len(); // Compile subtrees for each option @@ -1380,6 +1379,7 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, let mut bindings_map = FnvHashMap(); pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| { let ident = path1.node; + let name = ident.name; let variable_ty = node_id_type(bcx, p_id); let llvariable_ty = type_of::type_of(ccx, variable_ty); let tcx = bcx.tcx(); @@ -1396,7 +1396,7 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, "__llmatch"); trmode = TrByCopy(alloca_no_lifetime(bcx, llvariable_ty, - &bcx.ident(ident))); + &bcx.name(name))); } ast::BindByValue(_) => { // in this case, the final type of the variable will be T, @@ -1404,13 +1404,13 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, // above llmatch = alloca_no_lifetime(bcx, llvariable_ty.ptr_to(), - &bcx.ident(ident)); + &bcx.name(name)); trmode = TrByMove; } ast::BindByRef(_) => { llmatch = alloca_no_lifetime(bcx, llvariable_ty, - &bcx.ident(ident)); + &bcx.name(name)); trmode = TrByRef; } }; @@ -1527,7 +1527,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat_bindings(&tcx.def_map, pat, |_, p_id, _, path1| { let scope = cleanup::var_scope(tcx, p_id); bcx = mk_binding_alloca( - bcx, p_id, &path1.node, scope, (), + bcx, p_id, path1.node.name, scope, (), |(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx }); }); bcx @@ -1549,7 +1549,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(ident) => { let var_scope = cleanup::var_scope(tcx, local.id); return mk_binding_alloca( - bcx, pat.id, ident, var_scope, (), + bcx, pat.id, ident.name, var_scope, (), |(), bcx, v, _| expr::trans_into(bcx, &**init_expr, expr::SaveIn(v))); } @@ -1605,7 +1605,7 @@ pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bcx } else { mk_binding_alloca( - bcx, pat.id, ident, arg_scope, arg, + bcx, pat.id, ident.name, arg_scope, arg, |arg, bcx, llval, _| arg.store_to(bcx, llval)) } } @@ -1622,7 +1622,7 @@ pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, p_id: ast::NodeId, - ident: &ast::Ident, + name: ast::Name, cleanup_scope: cleanup::ScopeId, arg: A, populate: F) @@ -1632,7 +1632,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>, let var_ty = node_id_type(bcx, p_id); // Allocate memory on stack for the binding. - let llval = alloc_ty(bcx, var_ty, &bcx.ident(*ident)); + let llval = alloc_ty(bcx, var_ty, &bcx.name(name)); // Subtle: be sure that we *populate* the memory *before* // we schedule the cleanup. @@ -1686,7 +1686,7 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // binding will live and place it into the appropriate // map. bcx = mk_binding_alloca( - bcx, pat.id, &path1.node, cleanup_scope, (), + bcx, pat.id, path1.node.name, cleanup_scope, (), |(), bcx, llval, ty| { match pat_binding_mode { ast::BindByValue(_) => { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index fd1fff308d..de2ae970c8 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -45,8 +45,6 @@ pub use self::Repr::*; -#[allow(deprecated)] -use std::num::Int; use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; @@ -235,7 +233,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); - if cases.len() == 0 { + if cases.is_empty() { // Uninhabitable; represent as unit // (Typechecking will reject discriminant-sizing attrs.) assert_eq!(hint, attr::ReprAny); @@ -244,7 +242,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, dtor_to_init_u8(dtor)); } - if !dtor && cases.iter().all(|c| c.tys.len() == 0) { + if !dtor && cases.iter().all(|c| c.tys.is_empty()) { // All bodies empty -> intlike let discrs: Vec = cases.iter().map(|c| c.discr).collect(); let bounds = IntBounds { diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs new file mode 100644 index 0000000000..2615490a9f --- /dev/null +++ b/src/librustc_trans/trans/attributes.rs @@ -0,0 +1,281 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Set and unset common attributes on LLVM values. + +use libc::{c_uint, c_ulonglong}; +use llvm::{self, ValueRef, AttrHelper}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; +use syntax::ast; +pub use syntax::attr::InlineAttr; +use trans::base; +use trans::common; +use trans::context::CrateContext; +use trans::machine; +use trans::type_of; + +/// Mark LLVM function to use split stack. +#[inline] +pub fn split_stack(val: ValueRef, set: bool) { + unsafe { + let attr = "split-stack\0".as_ptr() as *const _; + if set { + llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } else { + llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } + } +} + +/// Mark LLVM function to use provided inline heuristic. +#[inline] +pub fn inline(val: ValueRef, inline: InlineAttr) { + use self::InlineAttr::*; + match inline { + Hint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), + Always => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), + Never => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), + None => { + let attr = llvm::InlineHintAttribute | + llvm::AlwaysInlineAttribute | + llvm::NoInlineAttribute; + unsafe { + llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong) + } + }, + }; +} + +/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. +#[inline] +pub fn emit_uwtable(val: ValueRef, emit: bool) { + if emit { + llvm::SetFunctionAttribute(val, llvm::UWTableAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong); + } + } +} + +/// Tell LLVM whether the function can or cannot unwind. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn unwind(val: ValueRef, can_unwind: bool) { + if can_unwind { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong); + } + } else { + llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute); + } +} + +/// Tell LLVM whether it should optimise function for size. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { + if optimize { + llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong); + } + } +} + +/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) +/// attributes. +pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { + use syntax::attr::*; + inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + + for attr in attrs { + if attr.check_name("no_stack_check") { + split_stack(llfn, false); + } else if attr.check_name("cold") { + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + llvm::FunctionIndex as c_uint, + llvm::ColdAttribute as u64) + } + } else if attr.check_name("allocator") { + llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } + } +} + +/// Composite function which converts function type into LLVM attributes for the function. +pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx>) + -> llvm::AttrBuilder { + use middle::ty::{BrAnon, ReLateBound}; + + let function_type; + let (fn_sig, abi, env_ty) = match fn_type.sty { + ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), + ty::ty_closure(closure_did, substs) => { + let typer = common::NormalizingClosureTyper::new(ccx.tcx()); + function_type = typer.closure_type(closure_did, substs); + let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); + (&function_type.sig, abi::RustCall, Some(self_type)) + } + _ => ccx.sess().bug("expected closure or function.") + }; + + let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + + let mut attrs = llvm::AttrBuilder::new(); + let ret_ty = fn_sig.output; + + // These have an odd calling convention, so we need to manually + // unpack the input ty's + let input_tys = match fn_type.sty { + ty::ty_closure(..) => { + assert!(abi == abi::RustCall); + + match fn_sig.inputs[0].sty { + ty::ty_tup(ref inputs) => { + let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; + full_inputs.push_all(inputs); + full_inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + }, + ty::ty_bare_fn(..) if abi == abi::RustCall => { + let mut inputs = vec![fn_sig.inputs[0]]; + + match fn_sig.inputs[1].sty { + ty::ty_tup(ref t_in) => { + inputs.push_all(&t_in[..]); + inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + } + _ => fn_sig.inputs.clone() + }; + + // Index 0 is the return value of the llvm func, so we start at 1 + let mut first_arg_offset = 1; + if let ty::FnConverging(ret_ty) = ret_ty { + // A function pointer is called without the declaration + // available, so we have to apply any attributes with ABI + // implications directly to the call instruction. Right now, + // the only attribute we need to worry about is `sret`. + if type_of::return_uses_outptr(ccx, ret_ty) { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); + + // The outptr can be noalias and nocapture because it's entirely + // invisible to the program. We also know it's nonnull as well + // as how many bytes we can dereference + attrs.arg(1, llvm::StructRetAttribute) + .arg(1, llvm::NoAliasAttribute) + .arg(1, llvm::NoCaptureAttribute) + .arg(1, llvm::DereferenceableAttribute(llret_sz)); + + // Add one more since there's an outptr + first_arg_offset += 1; + } else { + // The `noalias` attribute on the return value is useful to a + // function ptr caller. + match ret_ty.sty { + // `~` pointer return values never alias because ownership + // is transferred + ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => { + attrs.ret(llvm::NoAliasAttribute); + } + _ => {} + } + + // We can also mark the return value as `dereferenceable` in certain cases + match ret_ty.sty { + // These are not really pointers but pairs, (pointer, len) + ty::ty_rptr(_, ty::mt { ty: inner, .. }) + | ty::ty_uniq(inner) if common::type_is_sized(ccx.tcx(), inner) => { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + attrs.ret(llvm::DereferenceableAttribute(llret_sz)); + } + _ => {} + } + + if let ty::ty_bool = ret_ty.sty { + attrs.ret(llvm::ZExtAttribute); + } + } + } + + for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { + match t.sty { + // this needs to be first to prevent fat pointers from falling through + _ if !common::type_is_immediate(ccx, t) => { + let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t)); + + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); + } + + ty::ty_bool => { + attrs.arg(idx, llvm::ZExtAttribute); + } + + // `~` pointer parameters never alias because ownership is transferred + ty::ty_uniq(inner) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // `&mut` pointer parameters never alias other parameters, or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both + // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on + // memory dependencies rather than pointer equality + ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || + !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { + + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + + if mt.mutbl == ast::MutImmutable { + attrs.arg(idx, llvm::ReadOnlyAttribute); + } + + if let ReLateBound(_, BrAnon(_)) = *b { + attrs.arg(idx, llvm::NoCaptureAttribute); + } + } + + // When a reference in an argument has no named lifetime, it's impossible for that + // reference to escape this function (returned or stored beyond the call by a closure). + ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // & pointer parameters are also never null and we know exactly how + // many bytes we can dereference + ty::ty_rptr(_, mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + } + _ => () + } + } + + attrs +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 05c366a645..023f9e0bda 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -7,21 +7,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - -// trans.rs: Translate the completed AST to the LLVM IR. -// -// Some functions here, such as trans_block and trans_expr, return a value -- -// the result of the translation to LLVM -- while others, such as trans_fn, -// trans_impl, and trans_item, are called only for the side effect of adding a -// particular definition to the LLVM IR output we're producing. -// -// Hopefully useful general knowledge about trans: -// -// * There's no way to find out the Ty type of a ValueRef. Doing so -// would be "trying to get the eggs out of an omelette" (credit: -// pcwalton). You can, instead, find out its TypeRef by calling val_ty, -// but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, -// int) and rec(x=int, y=int, z=int) will have the same TypeRef. +//! Translate the completed AST to the LLVM IR. +//! +//! Some functions here, such as trans_block and trans_expr, return a value -- +//! the result of the translation to LLVM -- while others, such as trans_fn, +//! trans_impl, and trans_item, are called only for the side effect of adding a +//! particular definition to the LLVM IR output we're producing. +//! +//! Hopefully useful general knowledge about trans: +//! +//! * There's no way to find out the Ty type of a ValueRef. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, +//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, +//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. #![allow(non_camel_case_types)] @@ -33,19 +32,20 @@ use super::ModuleTranslation; use back::link::mangle_exported_name; use back::{link, abi}; use lint; -use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; -use middle::subst::{Subst, Substs}; +use middle::subst::Substs; use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size}; use session::config::{self, NoDebugInfo}; use session::Session; use trans::_match; use trans::adt; +use trans::attributes; use trans::build::*; use trans::builder::{Builder, noname}; use trans::callee; @@ -54,7 +54,7 @@ use trans::cleanup; use trans::closure; use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral}; use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use trans::common::{CrateContext, ExternMap, FunctionContext}; +use trans::common::{CrateContext, FunctionContext}; use trans::common::{Result, NodeIdAndSpan}; use trans::common::{node_id_type, return_type_is_void}; use trans::common::{type_is_immediate, type_is_zero_size, val_ty}; @@ -64,10 +64,10 @@ use trans::context::SharedCrateContext; use trans::controlflow; use trans::datum; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::foreign; use trans::glue; -use trans::inline; use trans::intrinsic; use trans::machine; use trans::machine::{llsize_of, llsize_of_real}; @@ -84,7 +84,7 @@ use util::sha2::Sha256; use util::nodemap::NodeMap; use arena::TypedArena; -use libc::{c_uint, uint64_t}; +use libc::c_uint; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; @@ -180,61 +180,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions -pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, - ty: Type, output: ty::FnOutput) -> ValueRef { - - let buf = CString::new(name).unwrap(); - let llfn: ValueRef = unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) - }; - - // diverging functions may unwind, but can never return normally - if output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); - } - - if ccx.tcx().sess.opts.cg.no_redzone - .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { - llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) - } - - llvm::SetFunctionCallConv(llfn, cc); - // Function addresses in Rust are never significant, allowing functions to be merged. - llvm::SetUnnamedAddr(llfn, true); - - if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { - set_split_stack(llfn); - } - - llfn -} - -// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions -pub fn decl_cdecl_fn(ccx: &CrateContext, - name: &str, - ty: Type, - output: Ty) -> ValueRef { - decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output)) -} - -// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions -pub fn get_extern_fn(ccx: &CrateContext, - externs: &mut ExternMap, - name: &str, - cc: llvm::CallConv, - ty: Type, - output: Ty) - -> ValueRef { - match externs.get(name) { - Some(n) => return *n, - None => {} - } - let f = decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); - externs.insert(name.to_string(), f); - f -} - fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str, did: ast::DefId) -> ValueRef { match ccx.externs().borrow().get(name) { @@ -242,10 +187,10 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, None => () } - let f = decl_rust_fn(ccx, fn_ty, name); + let f = declare::declare_rust_fn(ccx, name, fn_ty); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs[..], f); + attributes::from_fn_attrs(ccx, &attrs[..], f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -272,63 +217,6 @@ pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::Closu *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap() } -pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_ty: Ty<'tcx>, name: &str) -> ValueRef { - debug!("decl_rust_fn(fn_ty={}, name={:?})", - fn_ty.repr(ccx.tcx()), - name); - - let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty); - - debug!("decl_rust_fn: fn_ty={} (after normalized associated types)", - fn_ty.repr(ccx.tcx())); - - let function_type; // placeholder so that the memory ownership works out ok - - let (sig, abi, env) = match fn_ty.sty { - ty::ty_bare_fn(_, ref f) => { - (&f.sig, f.abi, None) - } - ty::ty_closure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); - let self_type = self_type_for_closure(ccx, closure_did, fn_ty); - let llenvironment_type = type_of_explicit_arg(ccx, self_type); - debug!("decl_rust_fn: function_type={} self_type={}", - function_type.repr(ccx.tcx()), - self_type.repr(ccx.tcx())); - (&function_type.sig, RustCall, Some(llenvironment_type)) - } - _ => ccx.sess().bug("expected closure or fn") - }; - - let sig = ty::erase_late_bound_regions(ccx.tcx(), sig); - let sig = ty::Binder(sig); - - debug!("decl_rust_fn: sig={} (after erasing regions)", - sig.repr(ccx.tcx())); - - let llfty = type_of_rust_fn(ccx, env, &sig, abi); - - debug!("decl_rust_fn: llfty={}", - ccx.tn().type_to_string(llfty)); - - let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */); - let attrs = get_fn_llvm_attributes(ccx, fn_ty); - attrs.apply_llfn(llfn); - - // (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above - - llfn -} - -pub fn decl_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - fn_ty: Ty<'tcx>, name: &str) -> ValueRef { - let llfn = decl_rust_fn(ccx, fn_ty, name); - llvm::SetLinkage(llfn, llvm::InternalLinkage); - llfn -} - pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, t: Ty<'tcx>) -> ValueRef { let name = csearch::get_symbol(&ccx.sess().cstore, did); @@ -337,23 +225,22 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, Some(n) => return *n, None => () } - unsafe { - let buf = CString::new(name.clone()).unwrap(); - let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); - // Thread-local statics in some other crate need to *always* be linked - // against in a thread-local fashion, so we need to be sure to apply the - // thread-local attribute locally if it was present remotely. If we - // don't do this then linker errors can be generated where the linker - // complains that one object files has a thread local version of the - // symbol and another one doesn't. - for attr in &*ty::get_attrs(ccx.tcx(), did) { - if attr.check_name("thread_local") { - llvm::set_thread_local(c, true); - } + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + // FIXME(nagisa): investigate whether it can be changed into define_global + let c = declare::declare_global(ccx, &name[..], ty); + // Thread-local statics in some other crate need to *always* be linked + // against in a thread-local fashion, so we need to be sure to apply the + // thread-local attribute locally if it was present remotely. If we + // don't do this then linker errors can be generated where the linker + // complains that one object files has a thread local version of the + // symbol and another one doesn't. + for attr in &*ty::get_attrs(ccx.tcx(), did) { + if attr.check_name("thread_local") { + llvm::set_thread_local(c, true); } - ccx.externs().borrow_mut().insert(name.to_string(), c); - return c; } + ccx.externs().borrow_mut().insert(name.to_string(), c); + return c; } fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -390,125 +277,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } -#[allow(dead_code)] // useful -pub fn set_optimize_for_size(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::OptimizeForSizeAttribute) -} - -pub fn set_no_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute) -} - -#[allow(dead_code)] // useful -pub fn set_no_unwind(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute) -} - -// Tell LLVM to emit the information necessary to unwind the stack for the -// function f. -pub fn set_uwtable(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::UWTableAttribute) -} - -pub fn set_inline_hint(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute) -} - -pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { - use syntax::attr::{find_inline_attr, InlineAttr}; - // Set the inline hint if there is one - match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) { - InlineAttr::Hint => set_inline_hint(llfn), - InlineAttr::Always => set_always_inline(llfn), - InlineAttr::Never => set_no_inline(llfn), - InlineAttr::None => { /* fallthrough */ } - } - - for attr in attrs { - let mut used = true; - match &attr.name()[..] { - "no_stack_check" => unset_split_stack(llfn), - "cold" => unsafe { - llvm::LLVMAddFunctionAttribute(llfn, - llvm::FunctionIndex as c_uint, - llvm::ColdAttribute as uint64_t) - }, - "allocator" => { - llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } -} - -pub fn set_always_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::AlwaysInlineAttribute) -} - -pub fn set_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -pub fn unset_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -// Double-check that we never ask LLVM to declare the same symbol twice. It -// silently mangles such symbols, breaking our linkage model. -pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: String) { - if ccx.all_llvm_symbols().borrow().contains(&sym) { - ccx.sess().bug(&format!("duplicate LLVM symbol: {}", sym)); - } - ccx.all_llvm_symbols().borrow_mut().insert(sym); -} - - -pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - did: ast::DefId, - t: Ty<'tcx>, - parent_id: ast::DefId, - substs: &Substs<'tcx>) - -> ValueRef { - let _icx = push_ctxt("trans_res_dtor"); - let did = inline::maybe_instantiate_inline(ccx, did); - - if !substs.types.is_empty() { - assert_eq!(did.krate, ast::LOCAL_CRATE); - - // Since we're in trans we don't care for any region parameters - let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); - - let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); - - val - } else if did.krate == ast::LOCAL_CRATE { - get_item_val(ccx, did.node) - } else { - let tcx = ccx.tcx(); - let name = csearch::get_symbol(&ccx.sess().cstore, did); - let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); - let llty = type_of_dtor(ccx, class_ty); - let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), - did, - &[glue::get_drop_glue_type(ccx, t)], - ty::mk_nil(ccx.tcx())); - get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - &name[..], - llvm::CCallConv, - llty, - dtor_ty) - } -} pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool) -> llvm::IntPredicate { @@ -798,6 +566,25 @@ fn cast_shift_rhs(op: ast::BinOp_, } } +pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, + val_t: Ty<'tcx>) -> (Type, u64) { + match val_t.sty { + ty::ty_int(t) => { + let llty = Type::int_from_ty(cx.ccx(), t); + let min = match t { + ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64, + ast::TyIs => i64::MIN as u64, + ast::TyI8 => i8::MIN as u64, + ast::TyI16 => i16::MIN as u64, + ast::TyI32 => i32::MIN as u64, + ast::TyI64 => i64::MIN as u64, + }; + (llty, min) + } + _ => unreachable!(), + } +} + pub fn fail_if_zero_or_overflows<'blk, 'tcx>( cx: Block<'blk, 'tcx>, call_info: NodeIdAndSpan, @@ -852,21 +639,7 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>( // signed division/remainder which would trigger overflow. For unsigned // integers, no action beyond checking for zero need be taken. if is_signed { - let (llty, min) = match rhs_t.sty { - ty::ty_int(t) => { - let llty = Type::int_from_ty(cx.ccx(), t); - let min = match t { - ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64, - ast::TyIs => i64::MIN as u64, - ast::TyI8 => i8::MIN as u64, - ast::TyI16 => i16::MIN as u64, - ast::TyI32 => i32::MIN as u64, - ast::TyI64 => i64::MIN as u64, - }; - (llty, min) - } - _ => unreachable!(), - }; + let (llty, min) = llty_and_min_for_signed_ty(cx, rhs_t); let minus_one = ICmp(bcx, llvm::IntEQ, rhs, C_integral(llty, !0, false), debug_loc); with_cond(bcx, minus_one, |bcx| { @@ -898,7 +671,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => { let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); llfn } } @@ -920,7 +693,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return (C_null(Type::i8(bcx.ccx())), bcx); } - let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + let attributes = attributes::from_fn_type(bcx.ccx(), fn_ty); match bcx.opt_node_id { None => { @@ -1692,9 +1465,9 @@ pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, } } -// trans_closure: Builds an LLVM function out of a source function. -// If the function closes over its environment a closure will be -// returned. +/// Builds an LLVM function out of a source function. +/// +/// If the function closes over its environment a closure will be returned. pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -1708,7 +1481,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); let _icx = push_ctxt("trans_closure"); - set_uwtable(llfndecl); + attributes::emit_uwtable(llfndecl, true); debug!("trans_closure(..., param_substs={})", param_substs.repr(ccx.tcx())); @@ -1827,8 +1600,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, finish_fn(&fcx, bcx, output_type, ret_debug_loc); } -// trans_fn: creates an LLVM function corresponding to a source language -// function. +/// Creates an LLVM function corresponding to a source language function. pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -1842,15 +1614,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let fn_ty = ty::node_id_to_type(ccx.tcx(), id); let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty)); let abi = ty::ty_fn_abi(fn_ty); - trans_closure(ccx, - decl, - body, - llfndecl, - param_substs, - id, - attrs, - output_type, - abi, + trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi, closure::ClosureEnv::NotClosure); } @@ -2195,27 +1959,24 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let llfn = get_item_val(ccx, item.id); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); if abi != Rust { - foreign::trans_rust_fn_with_foreign_abi(ccx, - &**decl, - &**body, - &item.attrs, - llfn, - empty_substs, - item.id, - None); + foreign::trans_rust_fn_with_foreign_abi(ccx, &**decl, &**body, &item.attrs, + llfn, empty_substs, item.id, None); } else { - trans_fn(ccx, - &**decl, - &**body, - llfn, - empty_substs, - item.id, - &item.attrs); + trans_fn(ccx, &**decl, &**body, llfn, empty_substs, item.id, &item.attrs); } - update_linkage(ccx, - llfn, - Some(item.id), + update_linkage(ccx, llfn, Some(item.id), if is_origin { OriginalTranslation } else { InlinedCopy }); + + if is_entry_fn(ccx.sess(), item.id) { + create_entry_wrapper(ccx, item.span, llfn); + // check for the #[rustc_error] annotation, which forces an + // error in trans. This is used to write compile-fail tests + // that actually test that compilation succeeds without + // reporting an error. + if ty::has_attr(ccx.tcx(), local_def(item.id), "rustc_error") { + ccx.tcx().sess.span_fatal(item.span, "compilation successful"); + } + } } } @@ -2251,8 +2012,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let mut v = TransItemVisitor{ ccx: ccx }; v.visit_expr(&**expr); - consts::trans_static(ccx, m, item.id); - let g = get_item_val(ccx, item.id); + let g = consts::trans_static(ccx, m, item.id); update_linkage(ccx, g, Some(item.id), OriginalTranslation); // Do static_assert checking. It can't really be done much earlier @@ -2304,7 +2064,25 @@ pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) { } } -fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::NodeId, + +// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions +pub fn register_fn_llvmty(ccx: &CrateContext, + sp: Span, + sym: String, + node_id: ast::NodeId, + cc: llvm::CallConv, + llfty: Type) -> ValueRef { + debug!("register_fn_llvmty id={} sym={}", node_id, sym); + + let llfn = declare::define_fn(ccx, &sym[..], cc, llfty, + ty::FnConverging(ty::mk_nil(ccx.tcx()))).unwrap_or_else(||{ + ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); + }); + finish_register_fn(ccx, sym, node_id, llfn); + llfn +} + +fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId, llfn: ValueRef) { ccx.item_symbols().borrow_mut().insert(node_id, sym); @@ -2313,25 +2091,12 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N // eh_personality functions need to be externally linkable. let def = ast_util::local_def(node_id); if ccx.tcx().lang_items.stack_exhausted() == Some(def) { - unset_split_stack(llfn); + attributes::split_stack(llfn, false); llvm::SetLinkage(llfn, llvm::ExternalLinkage); } if ccx.tcx().lang_items.eh_personality() == Some(def) { llvm::SetLinkage(llfn, llvm::ExternalLinkage); } - - - if is_entry_fn(ccx.sess(), node_id) { - // check for the #[rustc_error] annotation, which forces an - // error in trans. This is used to write compile-fail tests - // that actually test that compilation succeeds without - // reporting an error. - if ty::has_attr(ccx.tcx(), local_def(node_id), "rustc_error") { - ccx.tcx().sess.span_fatal(sp, "compilation successful"); - } - - create_entry_wrapper(ccx, sp, llfn); - } } fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -2350,196 +2115,10 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().span_bug(sp, "expected bare rust function") } - let llfn = decl_rust_fn(ccx, node_type, &sym[..]); - finish_register_fn(ccx, sp, sym, node_id, llfn); - llfn -} - -pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>) - -> llvm::AttrBuilder -{ - use middle::ty::{BrAnon, ReLateBound}; - - let function_type; - let (fn_sig, abi, env_ty) = match fn_ty.sty { - ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), - ty::ty_closure(closure_did, substs) => { - let typer = common::NormalizingClosureTyper::new(ccx.tcx()); - function_type = typer.closure_type(closure_did, substs); - let self_type = self_type_for_closure(ccx, closure_did, fn_ty); - (&function_type.sig, RustCall, Some(self_type)) - } - _ => ccx.sess().bug("expected closure or function.") - }; - - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); - - let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; - - // These have an odd calling convention, so we need to manually - // unpack the input ty's - let input_tys = match fn_ty.sty { - ty::ty_closure(..) => { - assert!(abi == RustCall); - - match fn_sig.inputs[0].sty { - ty::ty_tup(ref inputs) => { - let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; - full_inputs.push_all(inputs); - full_inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - }, - ty::ty_bare_fn(..) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; - - match fn_sig.inputs[1].sty { - ty::ty_tup(ref t_in) => { - inputs.push_all(&t_in[..]); - inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - } - _ => fn_sig.inputs.clone() - }; - - // Index 0 is the return value of the llvm func, so we start at 1 - let mut first_arg_offset = 1; - if let ty::FnConverging(ret_ty) = ret_ty { - // A function pointer is called without the declaration - // available, so we have to apply any attributes with ABI - // implications directly to the call instruction. Right now, - // the only attribute we need to worry about is `sret`. - if type_of::return_uses_outptr(ccx, ret_ty) { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); - - // The outptr can be noalias and nocapture because it's entirely - // invisible to the program. We also know it's nonnull as well - // as how many bytes we can dereference - attrs.arg(1, llvm::StructRetAttribute) - .arg(1, llvm::NoAliasAttribute) - .arg(1, llvm::NoCaptureAttribute) - .arg(1, llvm::DereferenceableAttribute(llret_sz)); - - // Add one more since there's an outptr - first_arg_offset += 1; - } else { - // The `noalias` attribute on the return value is useful to a - // function ptr caller. - match ret_ty.sty { - // `~` pointer return values never alias because ownership - // is transferred - ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(_) => { - attrs.ret(llvm::NoAliasAttribute); - } - _ => {} - } - - // We can also mark the return value as `dereferenceable` in certain cases - match ret_ty.sty { - // These are not really pointers but pairs, (pointer, len) - ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - attrs.ret(llvm::DereferenceableAttribute(llret_sz)); - } - _ => {} - } - - if let ty::ty_bool = ret_ty.sty { - attrs.ret(llvm::ZExtAttribute); - } - } - } - - for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { - match t.sty { - // this needs to be first to prevent fat pointers from falling through - _ if !type_is_immediate(ccx, t) => { - let llarg_sz = llsize_of_real(ccx, type_of::type_of(ccx, t)); - - // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases. It's also - // program-invisible so can't possibly capture - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); - } - - ty::ty_bool => { - attrs.arg(idx, llvm::ZExtAttribute); - } - - // `~` pointer parameters never alias because ownership is transferred - ty::ty_uniq(inner) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // `&mut` pointer parameters never alias other parameters, or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both - // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on - // memory dependencies rather than pointer equality - ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || - !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { - - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - - if mt.mutbl == ast::MutImmutable { - attrs.arg(idx, llvm::ReadOnlyAttribute); - } - - if let ReLateBound(_, BrAnon(_)) = *b { - attrs.arg(idx, llvm::NoCaptureAttribute); - } - } - - // When a reference in an argument has no named lifetime, it's impossible for that - // reference to escape this function (returned or stored beyond the call by a closure). - ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // & pointer parameters are also never null and we know exactly how - // many bytes we can dereference - ty::ty_rptr(_, mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); - } - _ => () - } - } - - attrs -} - -// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions -pub fn register_fn_llvmty(ccx: &CrateContext, - sp: Span, - sym: String, - node_id: ast::NodeId, - cc: llvm::CallConv, - llfty: Type) -> ValueRef { - debug!("register_fn_llvmty id={} sym={}", node_id, sym); - - let llfn = decl_fn(ccx, - &sym[..], - cc, - llfty, - ty::FnConverging(ty::mk_nil(ccx.tcx()))); - finish_register_fn(ccx, sp, sym, node_id, llfn); + let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(||{ + ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); + }); + finish_register_fn(ccx, sym, node_id, llfn); llfn } @@ -2550,27 +2129,35 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool { } } -// Create a _rust_main(args: ~[str]) function which will be called from the -// runtime rust_start function +/// Create the `main` function which will initialise the rust runtime and call users’ main +/// function. pub fn create_entry_wrapper(ccx: &CrateContext, - _sp: Span, + sp: Span, main_llfn: ValueRef) { let et = ccx.sess().entry_type.get().unwrap(); match et { config::EntryMain => { - create_entry_fn(ccx, main_llfn, true); + create_entry_fn(ccx, sp, main_llfn, true); } - config::EntryStart => create_entry_fn(ccx, main_llfn, false), + config::EntryStart => create_entry_fn(ccx, sp, main_llfn, false), config::EntryNone => {} // Do nothing. } fn create_entry_fn(ccx: &CrateContext, + sp: Span, rust_main: ValueRef, use_start_lang_item: bool) { let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type()); - let llfn = decl_cdecl_fn(ccx, "main", llfty, ty::mk_nil(ccx.tcx())); + let llfn = declare::define_cfn(ccx, "main", llfty, + ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.sess().span_err(sp, "entry symbol `main` defined multiple times"); + // FIXME: We should be smart and show a better diagnostic here. + ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead"); + ccx.sess().abort_if_errors(); + panic!(); + }); // FIXME: #16581: Marking a symbol in the executable with `dllexport` // linkage forces MinGW's linker to output a `.reloc` section for ASLR @@ -2645,10 +2232,9 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, None => {} } - match attr::first_attr_value_str_by_name(attrs, "export_name") { + match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { // Use provided name Some(name) => name.to_string(), - _ => ccx.tcx().map.with_path(id, |path| { if attr::contains_name(attrs, "no_mangle") { // Don't mangle @@ -2707,14 +2293,15 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } else { llvm::LLVMTypeOf(v) }; - if contains_null(&sym[..]) { - ccx.sess().fatal( - &format!("Illegal null byte in export_name \ - value: `{}`", sym)); - } - let buf = CString::new(sym.clone()).unwrap(); - let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, - buf.as_ptr()); + + // FIXME(nagisa): probably should be declare_global, because no definition + // is happening here, but we depend on it being defined here from + // const::trans_static. This all logic should be replaced. + let g = declare::define_global(ccx, &sym[..], + Type::from_ref(llty)).unwrap_or_else(||{ + ccx.sess().span_fatal(i.span, &format!("symbol `{}` is already defined", + sym)) + }); if attr::contains_name(&i.attrs, "thread_local") { @@ -2730,12 +2317,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let llfn = if abi == Rust { register_fn(ccx, i.span, sym, i.id, ty) } else { - foreign::register_rust_fn_with_foreign_abi(ccx, - i.span, - sym, - i.id) + foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id) }; - set_llvm_fn_attrs(ccx, &i.attrs, llfn); + attributes::from_fn_attrs(ccx, &i.attrs, llfn); llfn } @@ -2796,7 +2380,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - set_llvm_fn_attrs(ccx, &ni.attrs, llfn); + attributes::from_fn_attrs(ccx, &ni.attrs, llfn); llfn } ast::ForeignItemStatic(..) => { @@ -2813,7 +2397,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ccx.sess().bug("struct variant kind unexpected in get_item_val") } }; - assert!(args.len() != 0); + assert!(!args.is_empty()); let ty = ty::node_id_to_type(ccx.tcx(), id); let parent = ccx.tcx().map.get_parent(id); let enm = ccx.tcx().map.expect_item(parent); @@ -2828,7 +2412,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2850,7 +2434,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2885,7 +2469,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, } else { foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) }; - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); return llfn; } else { ccx.sess().span_bug(span, "expected bare rust function"); diff --git a/src/librustc_trans/trans/cabi_aarch64.rs b/src/librustc_trans/trans/cabi_aarch64.rs index 8ac4f84d6e..57dd222338 100644 --- a/src/librustc_trans/trans/cabi_aarch64.rs +++ b/src/librustc_trans/trans/cabi_aarch64.rs @@ -86,11 +86,91 @@ fn ty_size(ty: Type) -> usize { } } +fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> { + fn check_array(ty: Type) -> Option<(Type, u64)> { + let len = ty.array_length() as u64; + if len == 0 { + return None + } + let elt = ty.element_type(); + + // if our element is an HFA/HVA, so are we; multiply members by our len + is_homogenous_aggregate_ty(elt).map(|(base_ty, members)| (base_ty, len * members)) + } + + fn check_struct(ty: Type) -> Option<(Type, u64)> { + let str_tys = ty.field_types(); + if str_tys.len() == 0 { + return None + } + + let mut prev_base_ty = None; + let mut members = 0; + for opt_homog_agg in str_tys.iter().map(|t| is_homogenous_aggregate_ty(*t)) { + match (prev_base_ty, opt_homog_agg) { + // field isn't itself an HFA, so we aren't either + (_, None) => return None, + + // first field - store its type and number of members + (None, Some((field_ty, field_members))) => { + prev_base_ty = Some(field_ty); + members = field_members; + }, + + // 2nd or later field - give up if it's a different type; otherwise incr. members + (Some(prev_ty), Some((field_ty, field_members))) => { + if prev_ty != field_ty { + return None; + } + members += field_members; + } + } + } + + // Because of previous checks, we know prev_base_ty is Some(...) because + // 1. str_tys has at least one element; and + // 2. prev_base_ty was filled in (or we would've returned early) + let (base_ty, members) = (prev_base_ty.unwrap(), members); + + // Ensure there is no padding. + if ty_size(ty) == ty_size(base_ty) * (members as usize) { + Some((base_ty, members)) + } else { + None + } + } + + let homog_agg = match ty.kind() { + Float => Some((ty, 1)), + Double => Some((ty, 1)), + Array => check_array(ty), + Struct => check_struct(ty), + Vector => match ty_size(ty) { + 4|8 => Some((ty, 1)), + _ => None + }, + _ => None + }; + + // Ensure we have at most four uniquely addressable members + homog_agg.and_then(|(base_ty, members)| { + if members > 0 && members <= 4 { + Some((base_ty, members)) + } else { + None + } + }) +} + fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { if is_reg_ty(ty) { let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; return ArgType::direct(ty, None, None, attr); } + if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { + let llty = Type::array(&base_ty, members); + return ArgType::direct(ty, Some(llty), None, None); + } let size = ty_size(ty); if size <= 16 { let llty = if size <= 1 { @@ -114,6 +194,10 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType { let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; return ArgType::direct(ty, None, None, attr); } + if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { + let llty = Type::array(&base_ty, members); + return ArgType::direct(ty, Some(llty), None, None); + } let size = ty_size(ty); if size <= 16 { let llty = if size == 0 { diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs index 754b7ee5cf..8d946e2743 100644 --- a/src/librustc_trans/trans/cabi_x86_64.rs +++ b/src/librustc_trans/trans/cabi_x86_64.rs @@ -70,7 +70,7 @@ trait ClassList { impl ClassList for [RegClass] { fn is_pass_byval(&self) -> bool { - if self.len() == 0 { return false; } + if self.is_empty() { return false; } let class = self[0]; class == Memory @@ -79,7 +79,7 @@ impl ClassList for [RegClass] { } fn is_ret_bysret(&self) -> bool { - if self.len() == 0 { return false; } + if self.is_empty() { return false; } self[0] == Memory } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 9eb46d3ff5..0e8c33cd93 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -41,6 +41,7 @@ use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, use trans::consts; use trans::datum::*; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::glue; use trans::inline; @@ -183,7 +184,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) bcx.fcx.param_substs); // Nullary variants are not callable - assert!(vinfo.args.len() > 0); + assert!(!vinfo.args.is_empty()); Callee { bcx: bcx, @@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); - let llfn = - decl_internal_rust_fn(ccx, - tuple_fn_ty, - &function_name[..]); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, + "fn_pointer_shim"); + let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty); // let empty_substs = tcx.mk_substs(Substs::trans_empty()); @@ -498,7 +495,7 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( match map_node { ast_map::NodeVariant(v) => match v.node.kind { - ast::TupleVariantKind(ref args) => args.len() > 0, + ast::TupleVariantKind(ref args) => !args.is_empty(), _ => false }, ast_map::NodeStructCtor(_) => true, diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 19891e9307..61af5bfaef 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -126,6 +126,7 @@ use trans::callee; use trans::common; use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::glue; use middle::region; use trans::type_::Type; @@ -844,10 +845,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx Some(llpersonality) => llpersonality, None => { let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = base::decl_cdecl_fn(self.ccx, - "rust_eh_personality", - fty, - self.ccx.tcx().types.i32); + let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty, + self.ccx.tcx().types.i32); *personality = Some(f); f } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1aade3663..eb4acec255 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; +use trans::attributes; use trans::base::*; use trans::build::*; use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; @@ -20,6 +21,7 @@ use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::expr; use trans::monomorphize::{self, MonoId}; use trans::type_of::*; @@ -161,10 +163,14 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc mangle_internal_name_by_path_and_seq(path, "closure") }); - let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); + // Currently there’s only a single user of get_or_create_declaration_if_closure and it + // unconditionally defines the function, therefore we use define_* here. + let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", symbol)); + }); // set an inline hint for all closures - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?} (type {})", @@ -380,7 +386,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); - let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name); + let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty) + .unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index c5985e930e..2ba963a42e 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -31,6 +31,7 @@ use trans::cleanup; use trans::consts; use trans::datum; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -48,7 +49,6 @@ use std::ffi::CString; use std::cell::{Cell, RefCell}; use std::result::Result as StdResult; use std::vec::Vec; -use syntax::ast::Ident; use syntax::ast; use syntax::ast_map::{PathElem, PathName}; use syntax::codemap::{DUMMY_SP, Span}; @@ -146,33 +146,6 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -// Return the smallest part of `ty` which is unsized. Fails if `ty` is sized. -// 'Smallest' here means component of the static representation of the type; not -// the size of an object at runtime. -pub fn unsized_part_of_type<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.sty { - ty::ty_str | ty::ty_trait(..) | ty::ty_vec(..) => ty, - ty::ty_struct(def_id, substs) => { - let unsized_fields: Vec<_> = - ty::struct_fields(cx, def_id, substs) - .iter() - .map(|f| f.mt.ty) - .filter(|ty| !type_is_sized(cx, *ty)) - .collect(); - - // Exactly one of the fields must be unsized. - assert!(unsized_fields.len() == 1); - - unsized_part_of_type(cx, unsized_fields[0]) - } - _ => { - assert!(type_is_sized(cx, ty), - "unsized_part_of_type failed even though ty is unsized"); - panic!("called unsized_part_of_type with sized ty"); - } - } -} - // Some things don't need cleanups during unwinding because the // task can free them all at once later. Currently only things // that only contain scalars and shared boxes can avoid unwind @@ -622,8 +595,8 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { } pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() } - pub fn ident(&self, ident: Ident) -> String { - token::get_ident(ident).to_string() + pub fn name(&self, name: ast::Name) -> String { + token::get_name(name).to_string() } pub fn node_id_to_string(&self, id: ast::NodeId) -> String { @@ -872,9 +845,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let buf = CString::new(format!("str{}", gsym.usize())); - let buf = buf.unwrap(); - let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); + let sym = format!("str{}", gsym.usize()); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + cx.sess().bug(&format!("symbol `{}` is already defined", sym)); + }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c32cb28ec7..38136b03a2 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -25,6 +25,7 @@ use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; +use trans::declare; use trans::monomorphize; use trans::type_::Type; use trans::type_of; @@ -35,6 +36,7 @@ use util::ppaux::{Repr, ty_to_string}; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; +use syntax::parse::token; use syntax::ptr::P; pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) @@ -83,7 +85,7 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) ast::LitBool(b) => C_bool(cx, b), ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()), ast::LitBinary(ref data) => { - addr_of(cx, C_bytes(cx, &data[..]), "binary", e.id) + addr_of(cx, C_bytes(cx, &data[..]), "binary") } } } @@ -96,13 +98,16 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { fn addr_of_mut(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { unsafe { - let name = format!("{}{}\0", kind, id); - let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(), - name.as_ptr() as *const _); + // FIXME: this totally needs a better name generation scheme, perhaps a simple global + // counter? Also most other uses of gensym in trans. + let gsym = token::gensym("_"); + let name = format!("{}{}", kind, gsym.usize()); + let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", name)); + }); llvm::LLVMSetInitializer(gv, cv); SetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); @@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { match ccx.const_globals().borrow().get(&cv) { Some(&gv) => return gv, None => {} } - let gv = addr_of_mut(ccx, cv, kind, id); + let gv = addr_of_mut(ccx, cv, kind); unsafe { llvm::LLVMSetGlobalConstant(gv, True); } @@ -233,7 +237,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } }; - let lvalue = addr_of(ccx, val, "const", expr.id); + let lvalue = addr_of(ccx, val, "const"); ccx.const_values().borrow_mut().insert(key, lvalue); lvalue } @@ -250,7 +254,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &ty::expr_ty_adjusted(cx.tcx(), e)); let opt_adj = cx.tcx().adjustments.borrow().get(&e.id).cloned(); match opt_adj { - Some(ty::AdjustReifyFnPointer(_def_id)) => { + Some(ty::AdjustReifyFnPointer) => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } @@ -268,73 +272,56 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } - let second_autoref = match adj.autoref { - None => { - let (dv, dt) = const_deref(cx, llconst, ty); - llconst = dv; - - // If we derefed a fat pointer then we will have an - // open type here. So we need to update the type with - // the one returned from const_deref. - ety_adjusted = dt; - None - } - Some(ty::AutoUnsafe(_, opt_autoref)) | - Some(ty::AutoPtr(_, _, opt_autoref)) => { - if adj.autoderefs == 0 { - // Don't copy data to do a deref+ref - // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref", e.id); - } else { - // Seeing as we are deref'ing here and take a reference - // again to make the pointer part of the far pointer below, - // we just skip the whole thing. We still need the type - // though. This works even if we don't need to deref - // because of byref semantics. Note that this is not just - // an optimisation, it is necessary for mutable vectors to - // work properly. - ty = match ty::deref(ty, true) { - Some(mt) => mt.ty, - None => { - cx.sess().bug(&format!("unexpected dereferenceable type {}", - ty_to_string(cx.tcx(), ty))) - } - } - } - opt_autoref - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const first autoref {:?}", autoref)) - } - }; - match second_autoref { - None => {} - Some(box ty::AutoUnsafe(_, None)) | - Some(box ty::AutoPtr(_, _, None)) => { - llconst = addr_of(cx, llconst, "autoref", e.id); - } - Some(box ty::AutoUnsize(ref k)) => { - let info = - expr::unsized_info( - cx, k, e.id, ty, param_substs, - || const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32])); - - let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span); - let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); - let base = ptrcast(llconst, ptr_ty); - - let prev_const = cx.const_unsized().borrow_mut() - .insert(base, llconst); - assert!(prev_const.is_none() || prev_const == Some(llconst)); - assert_eq!(abi::FAT_PTR_ADDR, 0); - assert_eq!(abi::FAT_PTR_EXTRA, 1); - llconst = C_struct(cx, &[base, info], false); - } - Some(autoref) => { - cx.sess().span_bug(e.span, - &format!("unimplemented const second autoref {:?}", autoref)) + if adj.autoref.is_some() { + if adj.autoderefs == 0 { + // Don't copy data to do a deref+ref + // (i.e., skip the last auto-deref). + llconst = addr_of(cx, llconst, "autoref"); + ty = ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ty); } + } else { + let (dv, dt) = const_deref(cx, llconst, ty); + llconst = dv; + + // If we derefed a fat pointer then we will have an + // open type here. So we need to update the type with + // the one returned from const_deref. + ety_adjusted = dt; + } + + if let Some(target) = adj.unsize { + let target = monomorphize::apply_param_substs(cx.tcx(), + param_substs, + &target); + + let pointee_ty = ty::deref(ty, true) + .expect("consts: unsizing got non-pointer type").ty; + let (base, old_info) = if !type_is_sized(cx.tcx(), pointee_ty) { + // Normally, the source is a thin pointer and we are + // adding extra info to make a fat pointer. The exception + // is when we are upcasting an existing object fat pointer + // to use a different vtable. In that case, we want to + // load out the original data pointer so we can repackage + // it. + (const_get_elt(cx, llconst, &[abi::FAT_PTR_ADDR as u32]), + Some(const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]))) + } else { + (llconst, None) + }; + + let unsized_ty = ty::deref(target, true) + .expect("consts: unsizing got non-pointer target type").ty; + let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); + let base = ptrcast(base, ptr_ty); + let info = expr::unsized_info(cx, pointee_ty, unsized_ty, + old_info, param_substs); + + let prev_const = cx.const_unsized().borrow_mut() + .insert(base, llconst); + assert!(prev_const.is_none() || prev_const == Some(llconst)); + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + llconst = C_struct(cx, &[base, info], false); } } None => {} @@ -711,12 +698,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // If this isn't the address of a static, then keep going through // normal constant evaluation. let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of(cx, v, "ref", e.id) + addr_of(cx, v, "ref") } } ast::ExprAddrOf(ast::MutMutable, ref sub) => { let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of_mut(cx, v, "ref_mut_slice", e.id) + addr_of_mut(cx, v, "ref_mut_slice") } ast::ExprTup(ref es) => { let repr = adt::represent_type(cx, ety); @@ -794,7 +781,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, variant_did); - if vinfo.args.len() > 0 { + if !vinfo.args.is_empty() { // N-ary variant. expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } else { @@ -862,7 +849,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } -pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { +pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> ValueRef { unsafe { let _icx = push_ctxt("trans_static"); let g = base::get_item_val(ccx, id); @@ -888,6 +875,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { } } debuginfo::create_global_var_metadata(ccx, id, g); + g } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 8919a386a4..e54962dc08 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -20,6 +20,7 @@ use trans::base; use trans::builder::Builder; use trans::common::{ExternMap,BuilderRef_res}; use trans::debuginfo; +use trans::declare; use trans::monomorphize::MonoId; use trans::type_::{Type, TypeNames}; use middle::subst::Substs; @@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> { llsizingtypes: RefCell, Type>>, adt_reprs: RefCell, Rc>>>, type_hashcodes: RefCell, String>>, - all_llvm_symbols: RefCell>, int_type: Type, opaque_vec_type: Type, builder: BuilderRef_res, @@ -413,7 +413,6 @@ impl<'tcx> LocalCrateContext<'tcx> { llsizingtypes: RefCell::new(FnvHashMap()), adt_reprs: RefCell::new(FnvHashMap()), type_hashcodes: RefCell::new(FnvHashMap()), - all_llvm_symbols: RefCell::new(FnvHashSet()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), @@ -653,10 +652,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.type_hashcodes } - pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell> { - &self.local.all_llvm_symbols - } - pub fn stats<'a>(&'a self) -> &'a Stats { &self.shared.stats } @@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn( - ccx, $name, Type::func(&[], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn(ccx, $name, - Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret); } else if *key == $name { - let f = base::decl_cdecl_fn(ccx, stringify!($cname), - Type::func(&[$($arg),*], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, stringify!($cname), + Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 5b1ac88c20..8cecc39ec3 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -27,7 +27,6 @@ use middle::ty; use util::ppaux::Repr; use syntax::ast; -use syntax::ast::Ident; use syntax::ast_util; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -132,7 +131,9 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match b.expr { Some(ref e) => { - bcx = expr::trans_into(bcx, &**e, dest); + if !bcx.unreachable.get() { + bcx = expr::trans_into(bcx, &**e, dest); + } } None => { assert!(dest == expr::Ignore || bcx.unreachable.get()); @@ -321,7 +322,7 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, - opt_label: Option, + opt_label: Option, exit: usize) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_break_cont"); @@ -354,14 +355,14 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, - label_opt: Option) + label_opt: Option) -> Block<'blk, 'tcx> { return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_BREAK); } pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, - label_opt: Option) + label_opt: Option) -> Block<'blk, 'tcx> { return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_LOOP); } @@ -417,8 +418,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); - let expr_file_line = consts::addr_of(ccx, expr_file_line_const, - "panic_loc", call_info.id); + let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc"); let args = vec!(expr_file_line); let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem); let bcx = callee::trans_lang_call(bcx, @@ -450,8 +450,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::addr_of(ccx, file_line_const, - "panic_bounds_check_loc", call_info.id); + let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 2747288b60..159b101e85 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -196,8 +196,9 @@ use llvm::debuginfo::*; use metadata::csearch; use middle::subst::{self, Substs}; use trans::{self, adt, machine, type_of}; -use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, - C_bytes, NormalizingClosureTyper}; +use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes, + NormalizingClosureTyper}; +use trans::declare; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::monomorphize; use trans::type_::Type; @@ -531,7 +532,7 @@ impl<'tcx> TypeMap<'tcx> { // Maybe check that there is no self type here. let tps = substs.types.get_slice(subst::TypeSpace); - if tps.len() > 0 { + if !tps.is_empty() { output.push('<'); for &type_parameter in tps { @@ -773,11 +774,11 @@ pub fn create_global_var_metadata(cx: &CrateContext, let var_item = cx.tcx().map.get(node_id); - let (ident, span) = match var_item { + let (name, span) = match var_item { ast_map::NodeItem(item) => { match item.node { - ast::ItemStatic(..) => (item.ident, item.span), - ast::ItemConst(..) => (item.ident, item.span), + ast::ItemStatic(..) => (item.ident.name, item.span), + ast::ItemConst(..) => (item.ident.name, item.span), _ => { cx.sess() .span_bug(item.span, @@ -806,7 +807,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let variable_type = ty::node_id_to_type(cx.tcx(), node_id); let type_metadata = type_metadata(cx, variable_type, span); let namespace_node = namespace_for_item(cx, ast_util::local_def(node_id)); - let var_name = token::get_ident(ident).to_string(); + let var_name = token::get_name(name).to_string(); let linkage_name = namespace_node.mangled_name_of_contained_item(&var_name[..]); let var_scope = namespace_node.scope; @@ -861,7 +862,7 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) { let scope_metadata = scope_metadata(bcx.fcx, node_id, span); declare_local(bcx, - var_ident.node, + var_ident.node.name, datum.ty, scope_metadata, DirectVariable { alloca: datum.val }, @@ -889,14 +890,14 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ast_item = cx.tcx().map.find(node_id); - let variable_ident = match ast_item { + let variable_name = match ast_item { None => { cx.sess().span_bug(span, "debuginfo::create_captured_var_metadata: node not found"); } Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => { match pat.node { ast::PatIdent(_, ref path1, _) => { - path1.node + path1.node.name } _ => { cx.sess() @@ -950,7 +951,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; declare_local(bcx, - variable_ident, + variable_name, variable_type, scope_metadata, variable_access, @@ -963,7 +964,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// /// Adds the created metadata nodes directly to the crate's IR. pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - variable_ident: ast::Ident, + variable_name: ast::Name, binding: BindingInfo<'tcx>) { if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) || @@ -993,7 +994,7 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; declare_local(bcx, - variable_ident, + variable_name, binding.ty, scope_metadata, var_access, @@ -1048,7 +1049,7 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) { }; declare_local(bcx, - var_ident.node, + var_ident.node.name, datum.ty, scope_metadata, DirectVariable { alloca: datum.val }, @@ -1101,7 +1102,7 @@ pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if let Ok(code_snippet) = code_snippet { let bytes = code_snippet.as_bytes(); - if bytes.len() > 0 && &bytes[bytes.len()-1..] == b"}" { + if !bytes.is_empty() && &bytes[bytes.len()-1..] == b"}" { cleanup_span = Span { lo: node_span.hi - codemap::BytePos(1), hi: node_span.hi, @@ -1283,7 +1284,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fnitem = cx.tcx().map.get(fn_ast_id); - let (ident, fn_decl, generics, top_level_block, span, has_path) = match fnitem { + let (name, fn_decl, generics, top_level_block, span, has_path) = match fnitem { ast_map::NodeItem(ref item) => { if contains_nodebug_attribute(&item.attrs) { return FunctionDebugContext::FunctionWithoutDebugInfo; @@ -1291,7 +1292,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, match item.node { ast::ItemFn(ref fn_decl, _, _, ref generics, ref top_level_block) => { - (item.ident, fn_decl, generics, top_level_block, item.span, true) + (item.ident.name, fn_decl, generics, top_level_block, item.span, true) } _ => { cx.sess().span_bug(item.span, @@ -1306,7 +1307,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::FunctionWithoutDebugInfo; } - (impl_item.ident, + (impl_item.ident.name, &sig.decl, &sig.generics, body, @@ -1329,7 +1330,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, match expr.node { ast::ExprClosure(_, ref fn_decl, ref top_level_block) => { let name = format!("fn{}", token::gensym("fn")); - let name = token::str_to_ident(&name[..]); + let name = token::intern(&name[..]); (name, fn_decl, // This is not quite right. It should actually inherit // the generics of the enclosing function. @@ -1350,7 +1351,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::FunctionWithoutDebugInfo; } - (trait_item.ident, + (trait_item.ident.name, &sig.decl, &sig.generics, body, @@ -1394,7 +1395,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let mut function_name = String::from_str(&token::get_ident(ident)); + let mut function_name = String::from_str(&token::get_name(name)); let template_parameters = get_template_parameters(cx, generics, param_substs, @@ -1541,10 +1542,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, actual_self_type, codemap::DUMMY_SP); - let ident = special_idents::type_self; + let name = token::get_name(special_idents::type_self.name); - let ident = token::get_ident(ident); - let name = CString::new(ident.as_bytes()).unwrap(); + let name = CString::new(name.as_bytes()).unwrap(); let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), @@ -1673,7 +1673,7 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor { } fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - variable_ident: ast::Ident, + variable_name: ast::Name, variable_type: Ty<'tcx>, scope_metadata: DIScope, variable_access: VariableAccess, @@ -1684,7 +1684,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = span_start(cx, span).file.name.clone(); let file_metadata = file_metadata(cx, &filename[..]); - let name = token::get_ident(variable_ident); + let name = token::get_name(variable_name); let loc = span_start(cx, span); let type_metadata = type_metadata(cx, variable_type, span); @@ -2017,7 +2017,7 @@ struct StructMemberDescriptionFactory<'tcx> { impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { - if self.fields.len() == 0 { + if self.fields.is_empty() { return Vec::new(); } @@ -2029,7 +2029,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { self.fields.iter().enumerate().map(|(i, field)| { let name = if field.name == special_idents::unnamed_field.name { - "".to_string() + format!("__{}", i) } else { token::get_name(field.name).to_string() }; @@ -2107,9 +2107,12 @@ struct TupleMemberDescriptionFactory<'tcx> { impl<'tcx> TupleMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { - self.component_types.iter().map(|&component_type| { + self.component_types + .iter() + .enumerate() + .map(|(i, &component_type)| { MemberDescription { - name: "".to_string(), + name: format!("__{}", i), llvm_type: type_of::type_of(cx, component_type), type_metadata: type_metadata(cx, component_type, self.span), offset: ComputedMemberOffset, @@ -2207,7 +2210,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { adt::Univariant(ref struct_def, _) => { assert!(self.variants.len() <= 1); - if self.variants.len() == 0 { + if self.variants.is_empty() { vec![] } else { let (variant_type_metadata, @@ -2261,8 +2264,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // MemberDescription of the struct's single field. let sole_struct_member_description = MemberDescription { name: match non_null_variant.arg_names { - Some(ref names) => token::get_ident(names[0]).to_string(), - None => "".to_string() + Some(ref names) => token::get_name(names[0]).to_string(), + None => "__0".to_string() }, llvm_type: non_null_llvm_type, type_metadata: non_null_type_metadata, @@ -2429,11 +2432,16 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let mut arg_names: Vec<_> = match variant_info.arg_names { Some(ref names) => { names.iter() - .map(|ident| { - token::get_ident(*ident).to_string() - }).collect() + .map(|&name| token::get_name(name).to_string()) + .collect() + } + None => { + variant_info.args + .iter() + .enumerate() + .map(|(i, _)| format!("__{}", i)) + .collect() } - None => variant_info.args.iter().map(|_| "".to_string()).collect() }; // If this is not a univariant enum, there is also the discriminant field. @@ -3245,11 +3253,10 @@ fn create_scope_map(cx: &CrateContext, struct ScopeStackEntry { scope_metadata: DIScope, - ident: Option + name: Option } - let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, - ident: None }); + let mut scope_stack = vec!(ScopeStackEntry { scope_metadata: fn_metadata, name: None }); scope_map.insert(fn_ast_id, fn_metadata); // Push argument identifiers onto the stack so arguments integrate nicely @@ -3257,7 +3264,7 @@ fn create_scope_map(cx: &CrateContext, for arg in args { pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| { scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata, - ident: Some(path1.node) }); + name: Some(path1.node.name) }); scope_map.insert(node_id, fn_metadata); }) } @@ -3296,13 +3303,12 @@ fn create_scope_map(cx: &CrateContext, loc.col.to_usize() as c_uint) }; - scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, - ident: None }); + scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, name: None }); inner_walk(cx, scope_stack, scope_map); // pop artificial scopes - while scope_stack.last().unwrap().ident.is_some() { + while scope_stack.last().unwrap().name.is_some() { scope_stack.pop(); } @@ -3374,7 +3380,7 @@ fn create_scope_map(cx: &CrateContext, // scope stack and maybe introduce an artificial scope if pat_util::pat_is_binding(def_map, &*pat) { - let ident = path1.node; + let name = path1.node.name; // LLVM does not properly generate 'DW_AT_start_scope' fields // for variable DIEs. For this reason we have to introduce @@ -3401,7 +3407,7 @@ fn create_scope_map(cx: &CrateContext, // variables with the same name will cause the problem. let need_new_scope = scope_stack .iter() - .any(|entry| entry.ident.iter().any(|i| i.name == ident.name)); + .any(|entry| entry.name == Some(name)); if need_new_scope { // Create a new lexical scope and push it onto the stack @@ -3420,7 +3426,7 @@ fn create_scope_map(cx: &CrateContext, scope_stack.push(ScopeStackEntry { scope_metadata: scope_metadata, - ident: Some(ident) + name: Some(name) }); } else { @@ -3428,7 +3434,7 @@ fn create_scope_map(cx: &CrateContext, let prev_metadata = scope_stack.last().unwrap().scope_metadata; scope_stack.push(ScopeStackEntry { scope_metadata: prev_metadata, - ident: Some(ident) + name: Some(name) }); } } @@ -3828,7 +3834,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, output.push_str("fn("); let sig = ty::erase_late_bound_regions(cx.tcx(), sig); - if sig.inputs.len() > 0 { + if !sig.inputs.is_empty() { for ¶meter_type in &sig.inputs { push_debuginfo_type_name(cx, parameter_type, true, output); output.push_str(", "); @@ -3838,7 +3844,7 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } if sig.variadic { - if sig.inputs.len() > 0 { + if !sig.inputs.is_empty() { output.push_str(", ..."); } else { output.push_str("..."); @@ -3970,8 +3976,8 @@ fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc llvm::ValueRef { - let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; + let section_var_name = "__rustc_debug_gdb_scripts_section__"; let section_var = unsafe { llvm::LLVMGetNamedGlobal(ccx.llmod(), @@ -4085,10 +4091,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) unsafe { let llvm_type = Type::array(&Type::i8(ccx), section_contents.len() as u64); - let section_var = llvm::LLVMAddGlobal(ccx.llmod(), - llvm_type.to_ref(), - section_var_name.as_ptr() - as *const _); + + let section_var = declare::define_global(ccx, section_var_name, + llvm_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name)) + }); llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs new file mode 100644 index 0000000000..9e7449f670 --- /dev/null +++ b/src/librustc_trans/trans/declare.rs @@ -0,0 +1,261 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Declare various LLVM values. +//! +//! Prefer using functions and methods from this module rather than calling LLVM functions +//! directly. These functions do some additional work to ensure we do the right thing given +//! the preconceptions of trans. +//! +//! Some useful guidelines: +//! +//! * Use declare_* family of methods if you are declaring, but are not interested in defining the +//! ValueRef they return. +//! * Use define_* family of methods when you might be defining the ValueRef. +//! * When in doubt, define. +use llvm::{self, ValueRef}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; +use trans::attributes; +use trans::base; +use trans::common; +use trans::context::CrateContext; +use trans::monomorphize; +use trans::type_::Type; +use trans::type_of; +use util::ppaux::Repr; + +use std::ffi::CString; +use libc::c_uint; + + +/// Declare a global value. +/// +/// If there’s a value with the same name already declared, the function will return its ValueRef +/// instead. +pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef { + debug!("declare_global(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + unsafe { + llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + } +} + + +/// Declare a function. +/// +/// For rust functions use `declare_rust_fn` instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type, + output: ty::FnOutput) -> ValueRef { + debug!("declare_fn(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let llfn = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + }; + + llvm::SetFunctionCallConv(llfn, callconv); + // Function addresses in Rust are never significant, allowing functions to be merged. + llvm::SetUnnamedAddr(llfn, true); + + if output == ty::FnDiverging { + llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); + } + + if ccx.tcx().sess.opts.cg.no_redzone + .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { + llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) + } + + if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { + attributes::split_stack(llfn, true); + } + llfn +} + + +/// Declare a C ABI function. +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef { + declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output)) +} + + +/// Declare a Rust function. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx())); + let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type); + debug!("declare_rust_fn (after normalised associated types) fn_type={}", + fn_type.repr(ccx.tcx())); + + let function_type; // placeholder so that the memory ownership works out ok + let (sig, abi, env) = match fn_type.sty { + ty::ty_bare_fn(_, ref f) => { + (&f.sig, f.abi, None) + } + ty::ty_closure(closure_did, substs) => { + let typer = common::NormalizingClosureTyper::new(ccx.tcx()); + function_type = typer.closure_type(closure_did, substs); + let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); + let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type); + debug!("declare_rust_fn function_type={} self_type={}", + function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx())); + (&function_type.sig, abi::RustCall, Some(llenvironment_type)) + } + _ => ccx.sess().bug("expected closure or fn") + }; + + let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig)); + debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx())); + let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi); + debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty)); + + // it is ok to directly access sig.0.output because we erased all late-bound-regions above + let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output); + attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); + llfn +} + + +/// Declare a Rust function with internal linkage. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + let llfn = declare_rust_fn(ccx, name, fn_type); + llvm::SetLinkage(llfn, llvm::InternalLinkage); + llfn +} + + +/// Declare a global with an intention to define it. +/// +/// Use this function when you intend to define a global. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_global(ccx, name, ty)) + } +} + + +/// Declare a function with an intention to define it. +/// +/// For rust functions use `define_rust_fn` instead. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type, + output: ty::FnOutput) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_fn(ccx, name, callconv, fn_type, output)) + } +} + + +/// Declare a C ABI function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type, + output: ty::Ty) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_cfn(ccx, name, fn_type, output)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_rust_fn(ccx, name, fn_type)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_internal_rust_fn(ccx, name, fn_type)) + } +} + + +/// Get defined or externally defined (AvailableExternally linkage) value by name. +fn get_defined_value(ccx: &CrateContext, name: &str) -> Option { + debug!("get_defined_value(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; + if val.is_null() { + debug!("get_defined_value: {:?} value is null", name); + None + } else { + let (declaration, aext_link) = unsafe { + let linkage = llvm::LLVMGetLinkage(val); + (llvm::LLVMIsDeclaration(val) != 0, + linkage == llvm::AvailableExternallyLinkage as c_uint) + }; + debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name, + declaration, aext_link); + if !declaration || aext_link { + Some(val) + } else { + None + } + } +} diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5a79aa35bf..27919d645b 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -72,8 +72,7 @@ use trans::monomorphize; use trans::tvec; use trans::type_of; use middle::ty::{struct_fields, tup_fields}; -use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer, AutoUnsafe}; -use middle::ty::AutoPtr; +use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer}; use middle::ty::{self, Ty}; use middle::ty::MethodCall; use util::common::indenter; @@ -290,72 +289,39 @@ pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) { Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr)); } -// Retrieve the information we are losing (making dynamic) in an unsizing -// adjustment. -// -// The `unadjusted_val` argument is a bit funny. It is intended -// for use in an upcast, where the new vtable for an object will -// be drived from the old one. Hence it is a pointer to the fat -// pointer. -pub fn unsized_info_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - kind: &ty::UnsizeKind<'tcx>, - id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - unadjusted_val: ValueRef, // see above (*) - param_substs: &'tcx subst::Substs<'tcx>) - -> ValueRef { - unsized_info( - bcx.ccx(), - kind, - id, - unadjusted_ty, - param_substs, - || Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA]))) -} - -// Same as `unsize_info_bcx`, but does not require a bcx -- instead it -// takes an extra closure to compute the upcast vtable. -pub fn unsized_info<'ccx, 'tcx, MK_UPCAST_VTABLE>( - ccx: &CrateContext<'ccx, 'tcx>, - kind: &ty::UnsizeKind<'tcx>, - id: ast::NodeId, - unadjusted_ty: Ty<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>, - mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above - -> ValueRef - where MK_UPCAST_VTABLE: FnOnce() -> ValueRef -{ - debug!("unsized_info(kind={:?}, id={}, unadjusted_ty={})", - kind, id, unadjusted_ty.repr(ccx.tcx())); - match kind { - &ty::UnsizeLength(len) => C_uint(ccx, len), - &ty::UnsizeStruct(box ref k, tp_index) => match unadjusted_ty.sty { - ty::ty_struct(_, ref substs) => { - let ty_substs = substs.types.get_slice(subst::TypeSpace); - unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, - mk_upcast_vtable) - } - _ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}", - unadjusted_ty.repr(ccx.tcx()))) - }, - &ty::UnsizeVtable(ty::TyTrait { ref principal, .. }, _) => { +/// Retrieve the information we are losing (making dynamic) in an unsizing +/// adjustment. +/// +/// The `old_info` argument is a bit funny. It is intended for use +/// in an upcast, where the new vtable for an object will be drived +/// from the old one. +pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, + source: Ty<'tcx>, + target: Ty<'tcx>, + old_info: Option, + param_substs: &'tcx subst::Substs<'tcx>) + -> ValueRef { + let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target); + match (&source.sty, &target.sty) { + (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len), + (&ty::ty_trait(_), &ty::ty_trait(_)) => { + // For now, upcasts are limited to changes in marker + // traits, and hence never actually require an actual + // change to the vtable. + old_info.expect("unsized_info: missing old info for trait upcast") + } + (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => { // Note that we preserve binding levels here: - let substs = principal.0.substs.with_self_ty(unadjusted_ty).erase_regions(); + let substs = principal.0.substs.with_self_ty(source).erase_regions(); let substs = ccx.tcx().mk_substs(substs); let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: principal.def_id(), - substs: substs })); - let trait_ref = monomorphize::apply_param_substs(ccx.tcx(), - param_substs, - &trait_ref); + substs: substs })); consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), Type::vtable_ptr(ccx)) } - &ty::UnsizeUpcast(_) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - mk_upcast_vtable() - } + _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}", + source.repr(ccx.tcx()), + target.repr(ccx.tcx()))) } } @@ -379,7 +345,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum.to_string(bcx.ccx()), adjustment); match adjustment { - AdjustReifyFnPointer(_def_id) => { + AdjustReifyFnPointer => { // FIXME(#19925) once fn item types are // zero-sized, we'll need to do something here } @@ -387,202 +353,112 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // purely a type-level thing } AdjustDerefRef(ref adj) => { - let (autoderefs, use_autoref) = match adj.autoref { - // Extracting a value from a box counts as a deref, but if we are - // just converting Box<[T, ..n]> to Box<[T]> we aren't really doing - // a deref (and wouldn't if we could treat Box like a normal struct). - Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true), + let skip_reborrows = if adj.autoderefs == 1 && adj.autoref.is_some() { // We are a bit paranoid about adjustments and thus might have a re- // borrow here which merely derefs and then refs again (it might have - // a different region or mutability, but we don't care here. It might - // also be just in case we need to unsize. But if there are no nested - // adjustments then it should be a no-op). - Some(ty::AutoPtr(_, _, None)) | - Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => { - match datum.ty.sty { - // Don't skip a conversion from Box to &T, etc. - ty::ty_rptr(..) => { - let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1); - let method = bcx.tcx().method_map.borrow().get(&method_call).is_some(); - if method { - // Don't skip an overloaded deref. - (adj.autoderefs, true) - } else { - (adj.autoderefs - 1, false) - } + // a different region or mutability, but we don't care here). + match datum.ty.sty { + // Don't skip a conversion from Box to &T, etc. + ty::ty_rptr(..) => { + let method_call = MethodCall::autoderef(expr.id, 0); + if bcx.tcx().method_map.borrow().contains_key(&method_call) { + // Don't skip an overloaded deref. + 0 + } else { + 1 } - _ => (adj.autoderefs, true), } + _ => 0 } - _ => (adj.autoderefs, true) + } else { + 0 }; - if autoderefs > 0 { + if adj.autoderefs > skip_reborrows { // Schedule cleanup. let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id)); - datum = unpack_datum!( - bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs)); + datum = unpack_datum!(bcx, deref_multiple(bcx, expr, + lval.to_expr_datum(), + adj.autoderefs - skip_reborrows)); } // (You might think there is a more elegant way to do this than a - // use_autoref bool, but then you remember that the borrow checker exists). - if let (true, &Some(ref a)) = (use_autoref, &adj.autoref) { - datum = unpack_datum!(bcx, apply_autoref(a, - bcx, - expr, - datum)); + // skip_reborrows bool, but then you remember that the borrow checker exists). + if skip_reborrows == 0 && adj.autoref.is_some() { + datum = unpack_datum!(bcx, apply_autoref(bcx, expr, datum)); + } + + if let Some(target) = adj.unsize { + datum = unpack_datum!(bcx, unsize_pointer(bcx, datum, + bcx.monomorphize(&target))); } } } debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock::new(bcx, datum); - fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>, - bcx: Block<'blk, 'tcx>, + fn apply_autoref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) -> DatumBlock<'blk, 'tcx, Expr> { let mut bcx = bcx; - let mut datum = datum; - - let datum = match autoref { - &AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => { - debug!(" AutoPtr"); - if let &Some(box ref a) = a { - datum = unpack_datum!(bcx, apply_autoref(a, bcx, expr, datum)); - } - if !type_is_sized(bcx.tcx(), datum.ty) { - // Arrange cleanup - let lval = unpack_datum!(bcx, - datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id)); - unpack_datum!(bcx, ref_fat_ptr(bcx, lval)) - } else { - unpack_datum!(bcx, auto_ref(bcx, datum, expr)) - } - } - &ty::AutoUnsize(ref k) => { - debug!(" AutoUnsize"); - unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k)) - } - &ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => { - debug!(" AutoUnsizeUniq(UnsizeLength)"); - unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len)) - } - &ty::AutoUnsizeUniq(ref k) => { - debug!(" AutoUnsizeUniq"); - unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k)) - } - }; - DatumBlock::new(bcx, datum) + if !type_is_sized(bcx.tcx(), datum.ty) { + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "ref_fat_ptr", expr.id)); + ref_fat_ptr(bcx, lval) + } else { + auto_ref(bcx, datum, expr) + } } - fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + fn unsize_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + datum: Datum<'tcx, Expr>, + target: Ty<'tcx>) + -> DatumBlock<'blk, 'tcx, Expr> { let mut bcx = bcx; - let tcx = bcx.tcx(); - let datum_ty = datum.ty; - let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); - debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx())); - - let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs); - - // Arrange cleanup - let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id)); + let unsized_ty = ty::deref(target, true) + .expect("expr::unsize got non-pointer target type").ty; + debug!("unsize_lvalue(unsized_ty={})", unsized_ty.repr(bcx.tcx())); - // Compute the base pointer. This doesn't change the pointer value, - // but merely its type. - let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to(); - let base = if !type_is_sized(bcx.tcx(), lval.ty) { + // We do not arrange cleanup ourselves; if we already are an + // L-value, then cleanup will have already been scheduled (and + // the `datum.to_rvalue_datum` call below will emit code to zero + // the drop flag when moving out of the L-value). If we are an + // R-value, then we do not need to schedule cleanup. + let datum = unpack_datum!(bcx, datum.to_rvalue_datum(bcx, "__unsize_ref")); + + let pointee_ty = ty::deref(datum.ty, true) + .expect("expr::unsize got non-pointer datum type").ty; + let (base, old_info) = if !type_is_sized(bcx.tcx(), pointee_ty) { // Normally, the source is a thin pointer and we are // adding extra info to make a fat pointer. The exception // is when we are upcasting an existing object fat pointer // to use a different vtable. In that case, we want to // load out the original data pointer so we can repackage // it. - Load(bcx, get_dataptr(bcx, lval.val)) + (Load(bcx, get_dataptr(bcx, datum.val)), + Some(Load(bcx, get_len(bcx, datum.val)))) } else { - lval.val + (datum.val, None) }; + + let info = unsized_info(bcx.ccx(), pointee_ty, unsized_ty, + old_info, bcx.fcx.param_substs); + + // Compute the base pointer. This doesn't change the pointer value, + // but merely its type. + let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to(); let base = PointerCast(bcx, base, ptr_ty); - let llty = type_of::type_of(bcx.ccx(), unsized_ty); + let llty = type_of::type_of(bcx.ccx(), target); // HACK(eddyb) get around issues with lifetime intrinsics. let scratch = alloca_no_lifetime(bcx, llty, "__fat_ptr"); Store(bcx, base, get_dataptr(bcx, scratch)); Store(bcx, info, get_len(bcx, scratch)); - DatumBlock::new(bcx, Datum::new(scratch, unsized_ty, LvalueExpr)) - } - - fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - len: usize) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - - let datum_ty = datum.ty; - - debug!("unsize_unique_vec expr.id={} datum_ty={} len={}", - expr.id, datum_ty.repr(tcx), len); - - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.store_to` call below will emit code to zero the - // drop flag when moving out of the L-value). If we are an R-value, - // then we do not need to schedule cleanup. - - let ll_len = C_uint(bcx.ccx(), len); - let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty)); - let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None)); - let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique"); - - let base = get_dataptr(bcx, scratch.val); - let base = PointerCast(bcx, - base, - type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); - bcx = datum.store_to(bcx, base); - - Store(bcx, ll_len, get_len(bcx, scratch.val)); - DatumBlock::new(bcx, scratch.to_expr_datum()) - } - - fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &ast::Expr, - datum: Datum<'tcx, Expr>, - k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { - let mut bcx = bcx; - let tcx = bcx.tcx(); - - let datum_ty = datum.ty; - let unboxed_ty = match datum_ty.sty { - ty::ty_uniq(t) => t, - _ => bcx.sess().bug(&format!("Expected ty_uniq, found {}", - bcx.ty_to_string(datum_ty))) - }; - let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span)); - - // We do not arrange cleanup ourselves; if we already are an - // L-value, then cleanup will have already been scheduled (and - // the `datum.store_to` call below will emit code to zero the - // drop flag when moving out of the L-value). If we are an R-value, - // then we do not need to schedule cleanup. - - let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr"); - let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty); - let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to()); - bcx = datum.store_to(bcx, base); - - let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs); - Store(bcx, info, get_len(bcx, scratch.val)); - - DatumBlock::new(bcx, scratch.to_expr_datum()) + DatumBlock::new(bcx, Datum::new(scratch, target, RvalueExpr(Rvalue::new(ByRef)))) } } @@ -678,7 +554,7 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, trans_def(bcx, expr, bcx.def(expr.id)) } ast::ExprField(ref base, ident) => { - trans_rec_field(bcx, &**base, ident.node) + trans_rec_field(bcx, &**base, ident.node.name) } ast::ExprTupField(ref base, idx) => { trans_rec_tup_field(bcx, &**base, idx.node) @@ -777,9 +653,9 @@ fn trans_field<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, /// Translates `base.field`. fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, base: &ast::Expr, - field: ast::Ident) + field: ast::Name) -> DatumBlock<'blk, 'tcx, Expr> { - trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys)) + trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field, field_tys)) } /// Translates `base.`. @@ -1259,7 +1135,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefVariant(tid, vid, _) => { let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - if variant_info.args.len() > 0 { + if !variant_info.args.is_empty() { // N-ary variant. let llfn = callee::trans_fn_ref(bcx.ccx(), vid, ExprId(ref_expr.id), @@ -1654,11 +1530,26 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::UnNeg => { let datum = unpack_datum!(bcx, trans(bcx, sub_expr)); let val = datum.to_llscalarish(bcx); - let llneg = { + let (bcx, llneg) = { if ty::type_is_fp(un_ty) { - FNeg(bcx, val, debug_loc) + let result = FNeg(bcx, val, debug_loc); + (bcx, result) } else { - Neg(bcx, val, debug_loc) + let is_signed = ty::type_is_signed(un_ty); + let result = Neg(bcx, val, debug_loc); + let bcx = if bcx.ccx().check_overflow() && is_signed { + let (llty, min) = base::llty_and_min_for_signed_ty(bcx, un_ty); + let is_min = ICmp(bcx, llvm::IntEQ, val, + C_integral(llty, min, true), debug_loc); + with_cond(bcx, is_min, |bcx| { + let msg = InternedString::new( + "attempted to negate with overflow"); + controlflow::trans_fail(bcx, expr_info(expr), msg) + }) + } else { + bcx + }; + (bcx, result) } }; immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock() @@ -2233,7 +2124,7 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut bcx = bcx; let mut datum = datum; for i in 0..times { - let method_call = MethodCall::autoderef(expr.id, i); + let method_call = MethodCall::autoderef(expr.id, i as u32); datum = unpack_datum!(bcx, deref_once(bcx, expr, datum, method_call)); } DatumBlock { bcx: bcx, datum: datum } @@ -2265,10 +2156,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // converts from the `Smaht` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. - let datum = match method_call.adjustment { + let datum = if method_call.autoderef == 0 { + datum + } else { // Always perform an AutoPtr when applying an overloaded auto-deref - ty::AutoDeref(_) => unpack_datum!(bcx, auto_ref(bcx, datum, expr)), - _ => datum + unpack_datum!(bcx, auto_ref(bcx, datum, expr)) }; let ref_ty = // invoked methods have their LB regions instantiated diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e87a5865df..8f3a51a500 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -13,12 +13,14 @@ use back::link; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; +use trans::attributes; use trans::base::{llvm_linkage_by_name, push_ctxt}; use trans::base; use trans::build::*; use trans::cabi; use trans::common::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -27,7 +29,6 @@ use trans::type_of; use middle::ty::{self, Ty}; use middle::subst::Substs; -use std::ffi::CString; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; @@ -135,9 +136,7 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let buf = CString::new(ident.as_bytes()).unwrap(); - let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), - buf.as_ptr()); + let g1 = declare::declare_global(ccx, &ident[..], llty2); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -148,20 +147,35 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&ident); - let real_name = CString::new(real_name).unwrap(); - let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), - real_name.as_ptr()); + let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{ + ccx.sess().span_fatal(foreign_item.span, + &format!("symbol `{}` is already defined", ident)) + }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 } } - None => unsafe { - // Generate an external declaration. - let buf = CString::new(ident.as_bytes()).unwrap(); - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) - } + None => // Generate an external declaration. + declare::declare_global(ccx, &ident[..], llty), + } +} + +// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions +pub fn get_extern_fn(ccx: &CrateContext, + externs: &mut ExternMap, + name: &str, + cc: llvm::CallConv, + ty: Type, + output: Ty) + -> ValueRef { + match externs.get(name) { + Some(n) => return *n, + None => {} } + let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output)); + externs.insert(name.to_string(), f); + f } /// Registers a foreign function found in a library. Just adds a LLVM global. @@ -189,14 +203,8 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Create the LLVM value for the C extern fn let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); - let llfn = base::get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - name, - cc, - llfn_ty, - fty); + let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); add_argument_attributes(&tys, llfn); - llfn } @@ -471,7 +479,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { } let llfn = register_foreign_item_fn(ccx, abi, ty, &lname); - base::set_llvm_fn_attrs(ccx, &foreign_item.attrs, llfn); + attributes::from_fn_attrs(ccx, &foreign_item.attrs, llfn); // Unlike for other items, we shouldn't call // `base::update_linkage` here. Foreign items have // special linkage requirements, which are handled @@ -522,7 +530,8 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") }; - let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil(ccx.tcx()))); + let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty, + ty::FnConverging(ty::mk_nil(ccx.tcx()))); add_argument_attributes(&tys, llfn); debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})", ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn)); @@ -611,8 +620,10 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx().map.path_to_string(id), id, t.repr(tcx)); - let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); - base::set_llvm_fn_attrs(ccx, attrs, llfn); + let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", ps)); + }); + attributes::from_fn_attrs(ccx, attrs, llfn); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn } @@ -642,6 +653,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } + if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 { + ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \ + multiple functions being wrapped"); + } + let ptr = "the block\0".as_ptr(); let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, ptr as *const _); @@ -800,7 +816,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Perform the call itself debug!("calling llrustfn = {}, t = {}", ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx())); - let attributes = base::get_fn_llvm_attributes(ccx, t); + let attributes = attributes::from_fn_type(ccx, t); let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes)); // Get the return value where the foreign fn expects it. diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 32b4d14177..f974796e69 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -15,11 +15,13 @@ use back::abi; use back::link::*; -use llvm::{ValueRef, get_param}; use llvm; +use llvm::{ValueRef, get_param}; +use metadata::csearch; use middle::lang_items::ExchangeFreeFnLangItem; use middle::subst; use middle::subst::{Subst, Substs}; +use middle::ty::{self, Ty}; use trans::adt; use trans::adt::GetDtorType; // for tcx.dtor_type() use trans::base::*; @@ -30,13 +32,16 @@ use trans::cleanup::CleanupMethods; use trans::common::*; use trans::datum; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; +use trans::foreign; +use trans::inline; use trans::machine::*; +use trans::monomorphize; +use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of}; use trans::type_::Type; -use trans::type_of::{type_of, sizing_type_of, align_of}; -use middle::ty::{self, Ty}; -use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; +use util::ppaux::{ty_to_short_str, Repr}; use arena::TypedArena; use libc::c_uint; @@ -178,14 +183,15 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val // To avoid infinite recursion, don't `make_drop_glue` until after we've // added the entry to the `drop_glues` cache. if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) { - let llfn = decl_cdecl_fn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); + let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); ccx.drop_glues().borrow_mut().insert(t, llfn); return llfn; }; let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "drop"); - let llfn = decl_cdecl_fn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())); - note_unique_llvm_symbol(ccx, fn_nm.clone()); + let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm)); + }); ccx.available_drop_glues().borrow_mut().insert(t, fn_nm); let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t))); @@ -259,6 +265,40 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } +pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + did: ast::DefId, + t: Ty<'tcx>, + parent_id: ast::DefId, + substs: &Substs<'tcx>) + -> ValueRef { + let _icx = push_ctxt("trans_res_dtor"); + let did = inline::maybe_instantiate_inline(ccx, did); + + if !substs.types.is_empty() { + assert_eq!(did.krate, ast::LOCAL_CRATE); + + // Since we're in trans we don't care for any region parameters + let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); + + let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); + + val + } else if did.krate == ast::LOCAL_CRATE { + get_item_val(ccx, did.node) + } else { + let tcx = ccx.tcx(); + let name = csearch::get_symbol(&ccx.sess().cstore, did); + let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); + let llty = type_of_dtor(ccx, class_ty); + let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), + did, + &[get_drop_glue_type(ccx, t)], + ty::mk_nil(ccx.tcx())); + foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv, + llty, dtor_ty) + } +} + fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 62a6ede4c2..fc3c0841dd 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -14,6 +14,7 @@ use llvm; use llvm::{SequentiallyConsistent, Acquire, Release, AtomicXchg, ValueRef, TypeKind}; use middle::subst; use middle::subst::FnSpace; +use trans::adt; use trans::base::*; use trans::build::*; use trans::callee; @@ -683,6 +684,17 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } + (_, "discriminant_value") => { + let val_ty = substs.types.get(FnSpace, 0); + match val_ty.sty { + ty::ty_enum(..) => { + let repr = adt::represent_type(ccx, *val_ty); + adt::trans_get_discr(bcx, &*repr, llargs[0], Some(llret_ty)) + } + _ => C_null(llret_ty) + } + } + // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst (_, name) if name.starts_with("atomic_") => { diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 190e44c967..e346fb0d93 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -28,6 +28,7 @@ use trans::common::*; use trans::consts; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr::SaveIn; use trans::expr; use trans::glue; @@ -82,7 +83,7 @@ pub fn trans_impl(ccx: &CrateContext, for impl_item in impl_items { match impl_item.node { ast::MethodImplItem(ref sig, ref body) => { - if sig.generics.ty_params.len() == 0 { + if sig.generics.ty_params.is_empty() { let trans_everywhere = attr::requests_inline(&impl_item.attrs); for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) { let llfn = get_item_val(ccx, impl_item.id); @@ -590,10 +591,10 @@ pub fn trans_object_shim<'a, 'tcx>( // let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty); let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = - decl_internal_rust_fn(ccx, shim_fn_ty, &function_name); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); + let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig); @@ -756,8 +757,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, C_uint(ccx, align) ].into_iter().chain(methods).collect(); - let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), - "vtable", trait_ref.def_id().node); + let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c7857d6a77..7d568ff90e 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -19,43 +19,45 @@ pub use self::common::gensym_name; #[macro_use] mod macros; -mod inline; -mod monomorphize; -mod controlflow; -mod glue; -mod datum; -mod callee; -mod expr; -mod common; -mod context; -mod consts; -mod type_of; +mod adt; +mod asm; +mod attributes; +mod base; +mod basic_block; mod build; mod builder; -mod base; -mod _match; -mod closure; -mod tvec; -mod meth; mod cabi; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_arm; mod cabi_aarch64; +mod cabi_arm; mod cabi_mips; mod cabi_powerpc; +mod cabi_x86; +mod cabi_x86_64; +mod cabi_x86_win64; +mod callee; +mod cleanup; +mod closure; +mod common; +mod consts; +mod context; +mod controlflow; +mod datum; +mod debuginfo; +mod declare; +mod expr; mod foreign; +mod glue; +mod inline; mod intrinsic; -mod debuginfo; +mod llrepr; mod machine; -mod adt; -mod asm; +mod _match; +mod meth; +mod monomorphize; +mod tvec; mod type_; +mod type_of; mod value; -mod basic_block; -mod llrepr; -mod cleanup; #[derive(Copy, Clone)] pub struct ModuleTranslation { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index dcb21c5cd9..1c8d020494 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,11 +17,12 @@ use middle::subst; use middle::subst::{Subst, Substs}; use middle::traits; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use trans::base::{set_llvm_fn_attrs, set_inline_hint}; +use trans::attributes; use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; -use trans::base::{trans_fn, decl_internal_rust_fn}; +use trans::base::trans_fn; use trans::base; use trans::common::*; +use trans::declare; use trans::foreign; use middle::ty::{self, HasProjectionTypes, Ty}; use util::ppaux::Repr; @@ -143,7 +144,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) } else { - decl_internal_rust_fn(ccx, mono_ty, &s[..]) + // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below. + declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", s)); + }) }; ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); @@ -151,7 +155,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - set_llvm_fn_attrs(ccx, attrs, lldecl); + attributes::from_fn_attrs(ccx, attrs, lldecl); let is_first = !ccx.available_monomorphizations().borrow().contains(&s); if is_first { @@ -200,7 +204,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineAttr::Hint); match v.node.kind { ast::TupleVariantKind(ref args) => { trans_enum_variant(ccx, @@ -259,7 +263,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineAttr::Hint); base::trans_tuple_struct(ccx, &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \ diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 791b58d88a..b02fcb6cf0 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -361,7 +361,7 @@ fn iter_vec_loop<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, InBoundsGEP(bcx, data_ptr, &[loop_counter]) }; let bcx = f(bcx, lleltptr, vt.unit_ty); - let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1us), DebugLoc::None); + let plusone = Add(bcx, loop_counter, C_uint(bcx.ccx(), 1usize), DebugLoc::None); AddIncomingToPhi(loop_counter, plusone, bcx.llbb); let cond_val = ICmp(bcx, llvm::IntULT, plusone, count, DebugLoc::None); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 2e577a0bd1..9f01521313 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -21,8 +21,6 @@ use util::ppaux::Repr; use trans::type_::Type; -#[allow(deprecated)] -use std::num::Int; use syntax::abi; use syntax::ast; @@ -69,7 +67,7 @@ pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return inputs.iter().cloned().collect() } - if inputs.len() == 0 { + if inputs.is_empty() { return Vec::new() } @@ -359,14 +357,14 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> cx.tn().find_type("str_slice").unwrap() } else { let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); - let unsized_part = unsized_part_of_type(cx.tcx(), ty); + let unsized_part = ty::struct_tail(cx.tcx(), ty); let info_ty = match unsized_part.sty { ty::ty_str | ty::ty_vec(..) => { Type::uint_from_ty(cx, ast::TyUs) } ty::ty_trait(_) => Type::vtable_ptr(cx), _ => panic!("Unexpected type returned from \ - unsized_part_of_type: {} for ty={}", + struct_tail: {} for ty={}", unsized_part.repr(cx.tcx()), ty.repr(cx.tcx())) }; Type::struct_(cx, &[ptr_ty, info_ty], false) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 939142cff1..171c83d00e 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -56,12 +56,13 @@ use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; use middle::traits; use middle::ty::{self, RegionEscape, Ty}; -use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, +use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; +use util::nodemap::FnvHashSet; use util::ppaux::{self, Repr, UserString}; -use std::iter::{repeat, AdditiveIterator}; +use std::iter::repeat; use std::rc::Rc; use std::slice; use syntax::{abi, ast, ast_util}; @@ -160,7 +161,12 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) } Some(&rl::DefEarlyBoundRegion(space, index, id)) => { - ty::ReEarlyBound(id, space, index, lifetime.name) + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: id, + space: space, + index: index, + name: lifetime.name + }) } Some(&rl::DefFreeRegion(scope, id)) => { @@ -517,12 +523,13 @@ fn find_implied_output_region(input_tys: &[Ty], input_pats: Vec) lifetimes_for_params.push((input_pat, accumulator.len())); } - let implied_output_region = if lifetimes_for_params.iter().map(|&(_, n)| n).sum() == 1 { - assert!(possible_implied_output_region.is_some()); - possible_implied_output_region - } else { - None - }; + let implied_output_region = + if lifetimes_for_params.iter().map(|&(_, n)| n).sum::() == 1 { + assert!(possible_implied_output_region.is_some()); + possible_implied_output_region + } else { + None + }; (implied_output_region, lifetimes_for_params) } @@ -871,24 +878,11 @@ fn ast_type_binding_to_poly_projection_predicate<'tcx>( } } - if candidates.len() > 1 { - span_err!(tcx.sess, binding.span, E0217, - "ambiguous associated type: `{}` defined in multiple supertraits `{}`", - token::get_name(binding.item_name), - candidates.user_string(tcx)); - return Err(ErrorReported); - } - - let candidate = match candidates.pop() { - Some(c) => c, - None => { - span_err!(tcx.sess, binding.span, E0218, - "no associated type `{}` defined in `{}`", - token::get_name(binding.item_name), - trait_ref.user_string(tcx)); - return Err(ErrorReported); - } - }; + let candidate = try!(one_bound_for_assoc_type(tcx, + candidates, + &trait_ref.user_string(tcx), + &token::get_name(binding.item_name), + binding.span)); Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+ projection_ty: ty::ProjectionTy { // | @@ -1023,13 +1017,58 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, projection_bounds, bounds); - let result = ty::mk_trait(this.tcx(), trait_ref, existential_bounds); + let result = make_object_type(this, span, trait_ref, existential_bounds); debug!("trait_ref_to_object_type: result={}", result.repr(this.tcx())); result } +fn make_object_type<'tcx>(this: &AstConv<'tcx>, + span: Span, + principal: ty::PolyTraitRef<'tcx>, + bounds: ty::ExistentialBounds<'tcx>) + -> Ty<'tcx> { + let tcx = this.tcx(); + let object = ty::TyTrait { + principal: principal, + bounds: bounds + }; + let object_trait_ref = + object.principal_trait_ref_with_self_ty(tcx, tcx.types.err); + + // ensure the super predicates and stop if we encountered an error + if this.ensure_super_predicates(span, object.principal_def_id()).is_err() { + return tcx.types.err; + } + + let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = + traits::supertraits(tcx, object_trait_ref) + .flat_map(|tr| { + let trait_def = ty::lookup_trait_def(tcx, tr.def_id()); + trait_def.associated_type_names + .clone() + .into_iter() + .map(move |associated_type_name| (tr.def_id(), associated_type_name)) + }) + .collect(); + + for projection_bound in &object.bounds.projection_bounds { + let pair = (projection_bound.0.projection_ty.trait_ref.def_id, + projection_bound.0.projection_ty.item_name); + associated_types.remove(&pair); + } + + for (trait_def_id, name) in associated_types { + span_err!(tcx.sess, span, E0191, + "the value of the associated type `{}` (from the trait `{}`) must be specified", + name.user_string(tcx), + ty::item_path_str(tcx, trait_def_id)); + } + + ty::mk_trait(tcx, object.principal, object.bounds) +} + fn report_ambiguous_associated_type(tcx: &ty::ctxt, span: Span, type_str: &str, @@ -1041,6 +1080,81 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, type_str, trait_str, name); } +// Search for a bound on a type parameter which includes the associated item +// given by assoc_name. ty_param_node_id is the node id for the type parameter +// (which might be `Self`, but only if it is the `Self` of a trait, not an +// impl). This function will fail if there are no suitable bounds or there is +// any ambiguity. +fn find_bound_for_assoc_item<'tcx>(this: &AstConv<'tcx>, + ty_param_node_id: ast::NodeId, + assoc_name: ast::Name, + span: Span) + -> Result, ErrorReported> +{ + let tcx = this.tcx(); + + let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { + Ok(v) => v, + Err(ErrorReported) => { + return Err(ErrorReported); + } + }; + + // Ensure the super predicates and stop if we encountered an error. + if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { + return Err(ErrorReported); + } + + // Check that there is exactly one way to find an associated type with the + // correct name. + let suitable_bounds: Vec<_> = + traits::transitive_bounds(tcx, &bounds) + .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) + .collect(); + + let ty_param_name = tcx.type_parameter_def(ty_param_node_id).name; + one_bound_for_assoc_type(tcx, + suitable_bounds, + &token::get_name(ty_param_name), + &token::get_name(assoc_name), + span) +} + + +// Checks that bounds contains exactly one element and reports appropriate +// errors otherwise. +fn one_bound_for_assoc_type<'tcx>(tcx: &ty::ctxt<'tcx>, + bounds: Vec>, + ty_param_name: &str, + assoc_name: &str, + span: Span) + -> Result, ErrorReported> +{ + if bounds.is_empty() { + span_err!(tcx.sess, span, E0220, + "associated type `{}` not found for `{}`", + assoc_name, + ty_param_name); + return Err(ErrorReported); + } + + if bounds.len() > 1 { + span_err!(tcx.sess, span, E0221, + "ambiguous associated type `{}` in bounds of `{}`", + assoc_name, + ty_param_name); + + for bound in &bounds { + span_note!(tcx.sess, span, + "associated type `{}` could derive from `{}`", + ty_param_name, + bound.user_string(tcx)); + } + } + + Ok(bounds[0].clone()) +} + // Create a type from a a path to an associated type. // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C // and item_segment is the path segment for D. We return a type and a def for @@ -1061,10 +1175,55 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); - // Check that the path prefix given by ty/ty_path_def is a type parameter/Self. - match (&ty.sty, ty_path_def) { + // Find the type of the associated item, and the trait where the associated + // item is declared. + let bound = match (&ty.sty, ty_path_def) { + (_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => { + // `Self` in an impl of a trait - we have a concrete self type and a + // trait reference. + match tcx.map.expect_item(impl_id).node { + ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) => { + if this.ensure_super_predicates(span, trait_did).is_err() { + return (tcx.types.err, ty_path_def); + } + + let trait_segment = &trait_ref.path.segments.last().unwrap(); + let trait_ref = ast_path_to_mono_trait_ref(this, + &ExplicitRscope, + span, + PathParamMode::Explicit, + trait_did, + Some(ty), + trait_segment); + + let candidates: Vec = + traits::supertraits(tcx, ty::Binder(trait_ref.clone())) + .filter(|r| this.trait_defines_associated_type_named(r.def_id(), + assoc_name)) + .collect(); + + match one_bound_for_assoc_type(tcx, + candidates, + "Self", + &token::get_name(assoc_name), + span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } + _ => unreachable!() + } + } (&ty::ty_param(_), def::DefTyParam(..)) | - (&ty::ty_param(_), def::DefSelfTy(_)) => {} + (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => { + // A type parameter or Self, we need to find the associated item from + // a bound. + let ty_param_node_id = ty_path_def.local_node_id(); + match find_bound_for_assoc_item(this, ty_param_node_id, assoc_name, span) { + Ok(bound) => bound, + Err(ErrorReported) => return (tcx.types.err, ty_path_def), + } + } _ => { report_ambiguous_associated_type(tcx, span, @@ -1073,61 +1232,15 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, &token::get_name(assoc_name)); return (tcx.types.err, ty_path_def); } - } - - let ty_param_node_id = ty_path_def.local_node_id(); - let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; - - let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { - Ok(v) => v, - Err(ErrorReported) => { - return (tcx.types.err, ty_path_def); - } }; - // Ensure the super predicates and stop if we encountered an error. - if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { - return (this.tcx().types.err, ty_path_def); - } - - // Check that there is exactly one way to find an associated type with the - // correct name. - let mut suitable_bounds: Vec<_> = - traits::transitive_bounds(tcx, &bounds) - .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) - .collect(); - - if suitable_bounds.len() == 0 { - span_err!(tcx.sess, span, E0220, - "associated type `{}` not found for type parameter `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); - return (this.tcx().types.err, ty_path_def); - } - - if suitable_bounds.len() > 1 { - span_err!(tcx.sess, span, E0221, - "ambiguous associated type `{}` in bounds of `{}`", - token::get_name(assoc_name), - token::get_name(ty_param_name)); - - for suitable_bound in &suitable_bounds { - span_note!(this.tcx().sess, span, - "associated type `{}` could derive from `{}`", - token::get_name(ty_param_name), - suitable_bound.user_string(this.tcx())); - } - } - - let suitable_bound = suitable_bounds.pop().unwrap().clone(); - let trait_did = suitable_bound.0.def_id; - - let ty = this.projected_ty_from_poly_trait_ref(span, suitable_bound, assoc_name); + let trait_did = bound.0.def_id; + let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name); let item_did = if trait_did.krate == ast::LOCAL_CRATE { // `ty::trait_items` used below requires information generated // by type collection, which may be in progress at this point. - match this.tcx().map.expect_item(trait_did.node).node { + match tcx.map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { let item = trait_items.iter() .find(|i| i.ident.name == assoc_name) @@ -1137,7 +1250,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, _ => unreachable!() } } else { - let trait_items = ty::trait_items(this.tcx(), trait_did); + let trait_items = ty::trait_items(tcx, trait_did); let item = trait_items.iter().find(|i| i.name() == assoc_name); item.expect("missing associated type").def_id() }; @@ -1173,14 +1286,13 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx)); - let trait_ref = - ast_path_to_mono_trait_ref(this, - rscope, - span, - param_mode, - trait_def_id, - Some(self_ty), - trait_segment); + let trait_ref = ast_path_to_mono_trait_ref(this, + rscope, + span, + param_mode, + trait_def_id, + Some(self_ty), + trait_segment); debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx)); @@ -1220,20 +1332,20 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } -// Note that both base_segments and assoc_segments may be empty, although not at -// the same time. -pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, - rscope: &RegionScope, - span: Span, - param_mode: PathParamMode, - def: &def::Def, - opt_self_ty: Option>, - base_segments: &[ast::PathSegment], - assoc_segments: &[ast::PathSegment]) - -> Ty<'tcx> { +// Check the base def in a PathResolution and convert it to a Ty. If there are +// associated types in the PathResolution, these will need to be seperately +// resolved. +fn base_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment]) + -> Ty<'tcx> { let tcx = this.tcx(); - let base_ty = match *def { + match *def { def::DefTrait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details @@ -1257,18 +1369,28 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, } def::DefTy(did, _) | def::DefStruct(did) => { check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); - ast_path_to_ty(this, rscope, span, - param_mode, did, + ast_path_to_ty(this, + rscope, + span, + param_mode, + did, base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_param(tcx, space, index, name) } - def::DefSelfTy(_) => { - // N.b.: resolve guarantees that the this type only appears in a - // trait, which we rely upon in various places when creating - // substs. + def::DefSelfTy(_, Some((_, self_ty_id))) => { + // Self in impl (we know the concrete type). + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); + if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) { + ty + } else { + tcx.sess.span_bug(span, "self type has not been fully resolved") + } + } + def::DefSelfTy(Some(_), None) => { + // Self in trait. check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_self_type(tcx) } @@ -1288,6 +1410,9 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // FIXME(#22519) This part of the resolution logic should be // avoided entirely for that form, once we stop needed a Def // for `associated_path_def_to_ty`. + // Fixing this will also let use resolve ::Foo the same way we + // resolve Self::Foo, at the moment we can't resolve the former because + // we don't have the trait information around, which is just sad. if !base_segments.is_empty() { span_err!(tcx.sess, @@ -1308,11 +1433,29 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, "found value name used as a type: {:?}", *def); return this.tcx().types.err; } - }; + } +} - // If any associated type segments remain, attempt to resolve them. - let mut ty = base_ty; +// Note that both base_segments and assoc_segments may be empty, although not at +// the same time. +pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, + rscope: &RegionScope, + span: Span, + param_mode: PathParamMode, + def: &def::Def, + opt_self_ty: Option>, + base_segments: &[ast::PathSegment], + assoc_segments: &[ast::PathSegment]) + -> Ty<'tcx> { + let mut ty = base_def_to_ty(this, + rscope, + span, + param_mode, + def, + opt_self_ty, + base_segments); let mut def = *def; + // If any associated type segments remain, attempt to resolve them. for segment in assoc_segments { if ty.sty == ty::ty_err { break; @@ -1822,7 +1965,7 @@ fn conv_ty_poly_trait_ref<'tcx>( projection_bounds, partitioned_bounds); - ty::mk_trait(this.tcx(), main_trait_bound, bounds) + make_object_type(this, span, main_trait_bound, bounds) } pub fn conv_existential_bounds_from_partitioned_bounds<'tcx>( @@ -1887,7 +2030,7 @@ fn compute_object_lifetime_bound<'tcx>( "only a single explicit lifetime bound is permitted"); } - if explicit_region_bounds.len() != 0 { + if !explicit_region_bounds.is_empty() { // Explicitly specified region bound. Use that. let r = explicit_region_bounds[0]; return ast_region_to_region(tcx, r); @@ -1904,7 +2047,7 @@ fn compute_object_lifetime_bound<'tcx>( // If there are no derived region bounds, then report back that we // can find no region bound. - if derived_region_bounds.len() == 0 { + if derived_region_bounds.is_empty() { match rscope.object_lifetime_default(span) { Some(r) => { return r; } None => { @@ -1992,11 +2135,11 @@ pub fn partition_bounds<'a>(tcx: &ty::ctxt, &mut builtin_bounds) { let segments = &b.trait_ref.path.segments; let parameters = &segments[segments.len() - 1].parameters; - if parameters.types().len() > 0 { + if !parameters.types().is_empty() { check_type_argument_count(tcx, b.trait_ref.path.span, parameters.types().len(), 0, 0); } - if parameters.lifetimes().len() > 0{ + if !parameters.lifetimes().is_empty() { report_lifetime_number_error(tcx, b.trait_ref.path.span, parameters.lifetimes().len(), 0); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 8f1a67723c..0959f9d1b9 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -594,7 +594,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) { check_pat(pcx, &**subpat, *arg_ty); } - } else if arg_tys.len() == 0 { + } else if arg_tys.is_empty() { span_err!(tcx.sess, pat.span, E0024, "this pattern has {} field{}, but the corresponding {} has no fields", subpats.len(), if subpats.len() == 1 {""} else {"s"}, kind_name); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 3f9c14e0af..b065eb2d27 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -125,14 +125,10 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, adjusted_ty.repr(fcx.tcx()), autoderefs); - let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None }; - // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { ty::ty_bare_fn(..) => { - fcx.write_adjustment(callee_expr.id, - callee_expr.span, - ty::AdjustDerefRef(autoderefref)); + fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -149,14 +145,14 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &closure_ty.sig).0; - fcx.record_deferred_call_resolution( - def_id, - Box::new(CallResolution {call_expr: call_expr, - callee_expr: callee_expr, - adjusted_ty: adjusted_ty, - autoderefref: autoderefref, - fn_sig: fn_sig.clone(), - closure_def_id: def_id})); + fcx.record_deferred_call_resolution(def_id, Box::new(CallResolution { + call_expr: call_expr, + callee_expr: callee_expr, + adjusted_ty: adjusted_ty, + autoderefs: autoderefs, + fn_sig: fn_sig.clone(), + closure_def_id: def_id + })); return Some(CallStep::DeferredClosure(fn_sig)); } } @@ -176,7 +172,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, _ => {} } - try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefref) + try_overloaded_call_traits(fcx, call_expr, callee_expr, adjusted_ty, autoderefs) .map(|method_callee| CallStep::Overloaded(method_callee)) } @@ -184,7 +180,7 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &ast::Expr, callee_expr: &ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { // Try the options that are least restrictive on the caller first. @@ -203,7 +199,8 @@ fn try_overloaded_call_traits<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*callee_expr), method_name, trait_def_id, - autoderefref.clone(), + autoderefs, + false, adjusted_ty, None) { None => continue, @@ -335,7 +332,7 @@ struct CallResolution<'tcx> { call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>, + autoderefs: usize, fn_sig: ty::FnSig<'tcx>, closure_def_id: ast::DefId, } @@ -343,11 +340,11 @@ struct CallResolution<'tcx> { impl<'tcx> Repr<'tcx> for CallResolution<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \ - autoderefref={}, fn_sig={}, closure_def_id={})", + autoderefs={}, fn_sig={}, closure_def_id={})", self.call_expr.repr(tcx), self.callee_expr.repr(tcx), self.adjusted_ty.repr(tcx), - self.autoderefref.repr(tcx), + self.autoderefs, self.fn_sig.repr(tcx), self.closure_def_id.repr(tcx)) } @@ -364,7 +361,7 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { // We may now know enough to figure out fn vs fnmut etc. match try_overloaded_call_traits(fcx, self.call_expr, self.callee_expr, - self.adjusted_ty, self.autoderefref.clone()) { + self.adjusted_ty, self.autoderefs) { Some(method_callee) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature @@ -387,10 +384,11 @@ impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> { demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty); } + let nilty = ty::mk_nil(fcx.tcx()); demand::eqtype(fcx, self.call_expr.span, - method_sig.output.unwrap(), - self.fn_sig.output.unwrap()); + method_sig.output.unwrap_or(nilty), + self.fn_sig.output.unwrap_or(nilty)); write_overloaded_call_method_map(fcx, self.call_expr, method_callee); } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs new file mode 100644 index 0000000000..3773ff7078 --- /dev/null +++ b/src/librustc_typeck/check/cast.rs @@ -0,0 +1,190 @@ +// 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. + +//! Code for type-checking cast expressions. + +use super::coercion; +use super::demand; +use super::FnCtxt; +use super::structurally_resolved_type; + +use lint; +use middle::infer; +use middle::ty; +use middle::ty::Ty; +use syntax::ast; +use syntax::codemap::Span; + +/// Reifies a cast check to be checked once we have full type information for +/// a function context. +pub struct CastCheck<'tcx> { + expr: ast::Expr, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + span: Span, +} + +impl<'tcx> CastCheck<'tcx> { + pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) + -> CastCheck<'tcx> { + CastCheck { + expr: expr, + expr_ty: expr_ty, + cast_ty: cast_ty, + span: span, + } + } +} + +pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { + fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + span: Span, + t_1: Ty<'tcx>, + t_e: Ty<'tcx>) { + fcx.type_error_message(span, |actual| { + format!("illegal cast; cast through an \ + integer first: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } + + let span = cast.span; + let e = &cast.expr; + let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); + let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); + + // Check for trivial casts. + if !ty::type_has_ty_infer(t_1) { + if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { + if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, + e.id, + span, + format!("trivial numeric cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); + } else { + fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, + e.id, + span, + format!("trivial cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); + } + return; + } + } + + let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e); + let t_e_is_scalar = ty::type_is_scalar(t_e); + let t_e_is_integral = ty::type_is_integral(t_e); + let t_e_is_float = ty::type_is_floating_point(t_e); + let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); + + let t_1_is_scalar = ty::type_is_scalar(t_1); + let t_1_is_integral = ty::type_is_integral(t_1); + let t_1_is_char = ty::type_is_char(t_1); + let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); + let t_1_is_float = ty::type_is_floating_point(t_1); + let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); + + // casts to scalars other than `char` and `bare fn` are trivial + let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; + + if t_e_is_bare_fn_item && t_1_is_bare_fn { + demand::coerce(fcx, e.span, t_1, &e); + } else if t_1_is_char { + let t_e = fcx.infcx().shallow_resolve(t_e); + if t_e.sty != ty::ty_uint(ast::TyU8) { + fcx.type_error_message(span, |actual| { + format!("only `u8` can be cast as `char`, not `{}`", actual) + }, t_e, None); + } + } else if t_1.sty == ty::ty_bool { + span_err!(fcx.tcx().sess, span, E0054, + "cannot cast as `bool`, compare with zero instead"); + } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && + !(t_1_is_integral || t_1_is_float) { + // Casts from float must go through an integer + cast_through_integer_err(fcx, span, t_1, t_e) + } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && + !(t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { + // Casts to float must go through an integer or boolean + cast_through_integer_err(fcx, span, t_1, t_e) + } else if t_e_is_c_enum && t_1_is_trivial { + if ty::type_is_unsafe_ptr(t_1) { + // ... and likewise with C enum -> *T + cast_through_integer_err(fcx, span, t_1, t_e) + } + // casts from C-like enums are allowed + } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { + fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, + t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool { + match t1.sty { + ty::ty_vec(_, Some(_)) => {} + _ => return false + } + if ty::type_needs_infer(t2) { + // This prevents this special case from going off when casting + // to a type that isn't fully specified; e.g. `as *_`. (Issue + // #14893.) + return false + } + + let el = ty::sequence_element_type(fcx.tcx(), t1); + infer::mk_eqty(fcx.infcx(), + false, + infer::Misc(sp), + el, + t2).is_ok() + } + + // Due to the limitations of LLVM global constants, + // region pointers end up pointing at copies of + // vector elements instead of the original values. + // To allow unsafe pointers to work correctly, we + // need to special-case obtaining an unsafe pointer + // from a region pointer to a vector. + + /* this cast is only allowed from &[T, ..n] to *T or + &T to *T. */ + match (&t_e.sty, &t_1.sty) { + (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), + &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable })) + if types_compatible(fcx, e.span, mt1, mt2) => { + /* this case is allowed */ + } + _ => { + demand::coerce(fcx, e.span, t_1, &e); + } + } + } else if fcx.type_is_fat_ptr(t_e, span) && !fcx.type_is_fat_ptr(t_1, span) { + fcx.type_error_message(span, |actual| { + format!("illegal cast; cast from fat pointer: `{}` as `{}`", + actual, fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } else if !(t_e_is_scalar && t_1_is_trivial) { + /* + If more type combinations should be supported than are + supported here, then file an enhancement issue and + record the issue number in this comment. + */ + fcx.type_error_message(span, |actual| { + format!("non-scalar cast: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } +} diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ced6cec3ef..28df1c2159 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -61,21 +61,25 @@ //! we may want to adjust precisely when coercions occur. use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; +use check::vtable; use middle::infer::{self, Coercion}; use middle::subst; -use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; +use middle::traits; +use middle::ty::{AutoDerefRef, AdjustDerefRef}; use middle::ty::{self, mt, Ty}; use middle::ty_relate::RelateResult; use util::common::indent; use util::ppaux; use util::ppaux::Repr; +use std::cell::Cell; use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, origin: infer::TypeOrigin, + unsizing_obligation: Cell>> } type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; @@ -144,11 +148,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unpack_actual_value(a, |a| { match a.sty { - ty::ty_bare_fn(Some(a_def_id), a_f) => { + ty::ty_bare_fn(Some(_), a_f) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). - self.coerce_from_fn_item(a, a_def_id, a_f, b) + self.coerce_from_fn_item(a, a_f, b) } ty::ty_bare_fn(None, a_f) => { // We permit coercion of fn pointers to drop the @@ -184,18 +188,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match a.sty { ty::ty_rptr(_, mt_a) => { - if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { - return Err(ty::terr_mutability); - } + try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); } _ => return self.subtype(a, b) } let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); - let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); - let r_borrow = self.tcx().mk_region(r_borrow); + let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b)); + let lvalue_pref = match mutbl_b { ast::MutMutable => PreferMutLvalue, ast::MutImmutable => NoPreference @@ -229,7 +231,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(_) => { Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, - autoref: autoref + autoref: autoref, + unsize: None }))) } None => { @@ -257,183 +260,148 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // we can't unify [T] with U. But to properly support DST, we need to allow // that, at which point we will need extra checks on b here. - match (&a.sty, &b.sty) { - (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => { - match self.unsize_ty(t_a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let coercion = Coercion(self.origin.span()); - let r_borrow = self.fcx.infcx().next_region_var(coercion); - let ty = ty::mk_rptr(self.tcx(), - self.tcx().mk_region(r_borrow), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.subtype(ty, b)); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) - } - _ => Err(ty::terr_mismatch) + let (reborrow, target) = match (&a.sty, &b.sty) { + (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => { + if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) { + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + + let coercion = Coercion(self.origin.span()); + let r_borrow = self.fcx.infcx().next_region_var(coercion); + let region = self.tcx().mk_region(r_borrow); + (Some(ty::AutoPtr(region, mt_b.mutbl)), target) + } else { + return Err(ty::terr_mismatch); } } - (&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => { - match self.unsize_ty(t_a, mt_b.ty) { - Some((ty, kind)) => { - if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) { - return Err(ty::terr_mutability); - } - - let ty = ty::mk_ptr(self.tcx(), - ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.subtype(ty, b)); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoPtr(AutoUnsize({:?})))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mt_b.mutbl, - Some(box AutoUnsize(kind)))) - }))) - } - _ => Err(ty::terr_mismatch) + (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => { + if let Some(target) = self.unsize_ty(mt_a.ty, mt_b.ty) { + try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl)); + (Some(ty::AutoUnsafe(mt_b.mutbl)), target) + } else { + return Err(ty::terr_mismatch); } } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { - match self.unsize_ty(t_a, t_b) { - Some((ty, kind)) => { - let ty = ty::mk_uniq(self.tcx(), ty); - try!(self.subtype(ty, b)); - debug!("Success, coerced with AutoDerefRef(1, \ - AutoUnsizeUniq({:?}))", kind); - Ok(Some(AdjustDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(ty::AutoUnsizeUniq(kind)) - }))) - } - _ => Err(ty::terr_mismatch) + if let Some(target) = self.unsize_ty(t_a, t_b) { + (None, ty::mk_uniq(self.tcx(), target)) + } else { + return Err(ty::terr_mismatch); } } - _ => Err(ty::terr_mismatch) - } + _ => return Err(ty::terr_mismatch) + }; + + let target = ty::adjust_ty_for_autoref(self.tcx(), target, reborrow); + try!(self.subtype(target, b)); + let adjustment = AutoDerefRef { + autoderefs: if reborrow.is_some() { 1 } else { 0 }, + autoref: reborrow, + unsize: Some(target) + }; + debug!("Success, coerced with {}", adjustment.repr(self.tcx())); + Ok(Some(AdjustDerefRef(adjustment))) } - // Takes a type and returns an unsized version along with the adjustment - // performed to unsize it. - // E.g., `[T, ..n]` -> `([T], UnsizeLength(n))` + // Takes a type and returns an unsized version. + // E.g., `[T, ..n]` -> `[T]`. fn unsize_ty(&self, ty_a: Ty<'tcx>, ty_b: Ty<'tcx>) - -> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> - { + -> Option> { let tcx = self.tcx(); - self.unpack_actual_value(ty_a, |a| { - self.unpack_actual_value(ty_b, |b| { - debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); - match (&a.sty, &b.sty) { - (&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => { - let ty = ty::mk_vec(tcx, t_a, None); - Some((ty, ty::UnsizeLength(len))) - } - (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { - // Upcasts permit two things: - // - // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` - // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { - // construct a type `a1` which is a version of - // `a` using the upcast bounds from `b` - let bounds_a1 = ty::ExistentialBounds { - // From type b - region_bound: data_b.bounds.region_bound, - builtin_bounds: data_b.bounds.builtin_bounds, - - // From type a - projection_bounds: data_a.bounds.projection_bounds.clone(), - }; - let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); - - // relate `a1` to `b` - let result = self.fcx.infcx().commit_if_ok(|_| { - // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(infer::RelateObjectBound(self.origin.span()), - data_a.bounds.region_bound, - data_b.bounds.region_bound)); - self.subtype(ty_a1, ty_b) - }); - - // if that was successful, we have a coercion - match result { - Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))), - Err(_) => None, - } - } else { - None + self.unpack_actual_value(ty_a, |a| self.unpack_actual_value(ty_b, |b| { + debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); + match (&a.sty, &b.sty) { + (&ty::ty_vec(t_a, Some(_)), &ty::ty_vec(_, None)) => { + Some(ty::mk_vec(tcx, t_a, None)) + } + (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => { + // Upcasts permit two things: + // + // 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo` + // 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b` + // + // Note that neither of these changes requires any + // change at runtime. Eventually this will be + // generalized. + // + // We always upcast when we can because of reason + // #2 (region bounds). + if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) { + // construct a type `a1` which is a version of + // `a` using the upcast bounds from `b` + let bounds_a1 = ty::ExistentialBounds { + // From type b + region_bound: data_b.bounds.region_bound, + builtin_bounds: data_b.bounds.builtin_bounds, + + // From type a + projection_bounds: data_a.bounds.projection_bounds.clone(), + }; + let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); + + // relate `a1` to `b` + let result = self.fcx.infcx().commit_if_ok(|_| { + // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b + try!(self.outlives(infer::RelateObjectBound(self.origin.span()), + data_a.bounds.region_bound, + data_b.bounds.region_bound)); + self.subtype(ty_a1, ty_b) + }); + + // if that was successful, we have a coercion + match result { + Ok(_) => Some(ty_b), + Err(_) => None, } + } else { + None } - (_, &ty::ty_trait(ref data)) => { - Some((ty_b, ty::UnsizeVtable(ty::TyTrait { - principal: data.principal.clone(), - bounds: data.bounds.clone() - }, - ty_a))) - } - (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) - if did_a == did_b => { - debug!("unsizing a struct"); - // Try unsizing each type param in turn to see if we end up with ty_b. - let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); - let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); - assert!(ty_substs_a.len() == ty_substs_b.len()); - - let mut result = None; - let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); - for (i, (tp_a, tp_b)) in tps { - if self.subtype(*tp_a, *tp_b).is_ok() { - continue; - } - match self.unsize_ty(*tp_a, *tp_b) { - Some((new_tp, k)) => { - // Check that the whole types match. - let mut new_substs = substs_a.clone(); - new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; - let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); - if self.subtype(ty, ty_b).is_err() { - debug!("Unsized type parameter '{}', but still \ - could not match types {} and {}", - ppaux::ty_to_string(tcx, *tp_a), - ppaux::ty_to_string(tcx, ty), - ppaux::ty_to_string(tcx, ty_b)); - // We can only unsize a single type parameter, so - // if we unsize one and it doesn't give us the - // type we want, then we won't succeed later. - break; - } - - result = Some((ty, ty::UnsizeStruct(box k, i))); - break; - } - None => {} + } + (_, &ty::ty_trait(_)) => { + assert!(self.unsizing_obligation.get().is_none()); + self.unsizing_obligation.set(Some(a)); + Some(ty_b) + } + (&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b)) + if did_a == did_b => { + debug!("unsizing a struct"); + // Try unsizing each type param in turn to see if we end up with ty_b. + let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace); + let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace); + assert!(ty_substs_a.len() == ty_substs_b.len()); + + let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); + for (i, (tp_a, tp_b)) in tps { + if self.subtype(*tp_a, *tp_b).is_ok() { + continue; + } + if let Some(new_tp) = self.unsize_ty(tp_a, tp_b) { + // Check that the whole types match. + let mut new_substs = substs_a.clone(); + new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; + let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); + if self.subtype(ty, ty_b).is_err() { + debug!("Unsized type parameter '{}', but still \ + could not match types {} and {}", + ppaux::ty_to_string(tcx, tp_a), + ppaux::ty_to_string(tcx, ty), + ppaux::ty_to_string(tcx, ty_b)); + // We can only unsize a single type parameter, so + // if we unsize one and it doesn't give us the + // type we want, then we won't succeed later. + break; } + + return Some(ty); } - result } - _ => None + None } - }) - }) + _ => None + } + })) } fn coerce_from_fn_pointer(&self, @@ -451,29 +419,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { debug!("coerce_from_fn_pointer(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx())); - match b.sty { - ty::ty_bare_fn(None, fn_ty_b) => { - match (fn_ty_a.unsafety, fn_ty_b.unsafety) { - (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { - let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); - try!(self.subtype(unsafe_a, b)); - Ok(Some(ty::AdjustUnsafeFnPointer)) - } - _ => { - self.subtype(a, b) - } + if let ty::ty_bare_fn(None, fn_ty_b) = b.sty { + match (fn_ty_a.unsafety, fn_ty_b.unsafety) { + (ast::Unsafety::Normal, ast::Unsafety::Unsafe) => { + let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); + try!(self.subtype(unsafe_a, b)); + return Ok(Some(ty::AdjustUnsafeFnPointer)); } - } - _ => { - return self.subtype(a, b) + _ => {} } } + self.subtype(a, b) }) } fn coerce_from_fn_item(&self, a: Ty<'tcx>, - fn_def_id_a: ast::DefId, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { @@ -490,11 +451,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::ty_bare_fn(None, _) => { let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a); try!(self.subtype(a_fn_pointer, b)); - Ok(Some(ty::AdjustReifyFnPointer(fn_def_id_a))) - } - _ => { - return self.subtype(a, b) + Ok(Some(ty::AdjustReifyFnPointer)) } + _ => self.subtype(a, b) } }) } @@ -518,16 +477,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Check that the types which they point at are compatible. let a_unsafe = ty::mk_ptr(self.tcx(), ty::mt{ mutbl: mutbl_b, ty: mt_a.ty }); try!(self.subtype(a_unsafe, b)); - if !can_coerce_mutbls(mt_a.mutbl, mutbl_b) { - return Err(ty::terr_mutability); - } + try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that // regionck knows that the region for `a` must be valid here. Ok(Some(AdjustDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mutbl_b, None)) + autoref: Some(ty::AutoUnsafe(mutbl_b)), + unsize: None }))) } } @@ -538,27 +496,59 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); - let adjustment = try!(indent(|| { + let (adjustment, unsizing_obligation) = try!(indent(|| { fcx.infcx().commit_if_ok(|_| { - Coerce { + let coerce = Coerce { fcx: fcx, origin: infer::ExprAssignable(expr.span), - }.coerce(expr, a, b) + unsizing_obligation: Cell::new(None) + }; + Ok((try!(coerce.coerce(expr, a, b)), + coerce.unsizing_obligation.get())) }) })); + + if let Some(AdjustDerefRef(auto)) = adjustment { + if let (Some(source), Some(target)) = (unsizing_obligation, auto.unsize) { + let target = ty::deref(target, true) + .expect("coercion: unsizing got non-pointer target type").ty; + let target = ty::struct_tail(fcx.tcx(), target); + if let ty::ty_trait(ref ty_trait) = target.sty { + vtable::check_object_safety(fcx.tcx(), ty_trait, expr.span); + + // If the type is `Foo+'a`, ensures that the type + // being cast to `Foo+'a` implements `Foo`: + vtable::register_object_cast_obligations(fcx, + expr.span, + ty_trait, + source); + + // If the type is `Foo+'a`, ensures that the type + // being cast to `Foo+'a` outlives `'a`: + let cause = traits::ObligationCause { + span: expr.span, + body_id: fcx.body_id, + code: traits::ObjectCastObligation(source) + }; + fcx.register_region_obligation(source, ty_trait.bounds.region_bound, cause); + } + } + } + if let Some(adjustment) = adjustment { - fcx.write_adjustment(expr.id, expr.span, adjustment); + debug!("Success, coerced with {}", adjustment.repr(fcx.tcx())); + fcx.write_adjustment(expr.id, adjustment); } Ok(()) } -fn can_coerce_mutbls(from_mutbl: ast::Mutability, - to_mutbl: ast::Mutability) - -> bool { +fn coerce_mutbls<'tcx>(from_mutbl: ast::Mutability, + to_mutbl: ast::Mutability) + -> CoerceResult<'tcx> { match (from_mutbl, to_mutbl) { - (ast::MutMutable, ast::MutMutable) => true, - (ast::MutImmutable, ast::MutImmutable) => true, - (ast::MutMutable, ast::MutImmutable) => true, - (ast::MutImmutable, ast::MutMutable) => false, + (ast::MutMutable, ast::MutMutable) | + (ast::MutImmutable, ast::MutImmutable) | + (ast::MutMutable, ast::MutImmutable) => Ok(None), + (ast::MutImmutable, ast::MutMutable) => Err(ty::terr_mutability) } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 6aefcf5a47..7eb15a1479 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -24,7 +24,6 @@ use middle::infer::InferCtxt; use syntax::ast; use syntax::codemap::Span; use std::rc::Rc; -use std::mem; use std::iter::repeat; use util::ppaux::Repr; @@ -84,7 +83,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { -> MethodCallee<'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. - let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick.adjustment); + let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); // Make sure nobody calls `drop()` explicitly. self.enforce_illegal_method_limitations(&pick); @@ -134,11 +133,23 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn adjust_self_ty(&mut self, unadjusted_self_ty: Ty<'tcx>, - adjustment: &probe::PickAdjustment) + pick: &probe::Pick<'tcx>) -> Ty<'tcx> { - // Construct the actual adjustment and write it into the table - let auto_deref_ref = self.create_ty_adjustment(adjustment); + let (autoref, unsize) = if let Some(mutbl) = pick.autoref { + let region = self.infcx().next_region_var(infer::Autoref(self.span)); + let autoref = ty::AutoPtr(self.tcx().mk_region(region), mutbl); + (Some(autoref), pick.unsize.map(|target| { + ty::adjust_ty_for_autoref(self.tcx(), target, Some(autoref)) + })) + } else { + // No unsizing should be performed without autoref (at + // least during method dispach). This is because we + // currently only unsize `[T;N]` to `[T]`, and naturally + // that must occur being a reference. + assert!(pick.unsize.is_none()); + (None, None) + }; // Commit the autoderefs by calling `autoderef again, but this // time writing the results into the various tables. @@ -149,47 +160,27 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { UnresolvedTypeAction::Error, NoPreference, |_, n| { - if n == auto_deref_ref.autoderefs { + if n == pick.autoderefs { Some(()) } else { None } }); - assert_eq!(n, auto_deref_ref.autoderefs); + assert_eq!(n, pick.autoderefs); assert_eq!(result, Some(())); - let final_ty = - ty::adjust_ty_for_autoref(self.tcx(), self.span, autoderefd_ty, - auto_deref_ref.autoref.as_ref()); - // Write out the final adjustment. - self.fcx.write_adjustment(self.self_expr.id, self.span, ty::AdjustDerefRef(auto_deref_ref)); - - final_ty - } + self.fcx.write_adjustment(self.self_expr.id, + ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: pick.autoderefs, + autoref: autoref, + unsize: unsize + })); - fn create_ty_adjustment(&mut self, - adjustment: &probe::PickAdjustment) - -> ty::AutoDerefRef<'tcx> - { - match *adjustment { - probe::AutoDeref(num) => { - ty::AutoDerefRef { - autoderefs: num, - autoref: None, - } - } - probe::AutoUnsizeLength(autoderefs, len) => { - ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))), - } - } - probe::AutoRef(mutability, ref sub_adjustment) => { - let deref = self.create_ty_adjustment(&**sub_adjustment); - let region = self.infcx().next_region_var(infer::Autoref(self.span)); - wrap_autoref(deref, |base| ty::AutoPtr(region, mutability, base)) - } + if let Some(target) = unsize { + target + } else { + ty::adjust_ty_for_autoref(self.tcx(), autoderefd_ty, autoref) } } @@ -499,10 +490,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { .adjustments .borrow() .get(&expr.id) { - Some(&ty::AdjustDerefRef(ty::AutoDerefRef { - autoderefs: autoderef_count, - autoref: _ - })) => autoderef_count, + Some(&ty::AdjustDerefRef(ref adj)) => adj.autoderefs, Some(_) | None => 0, }; @@ -529,17 +517,6 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { if i != 0 { match expr.node { ast::ExprIndex(ref base_expr, ref index_expr) => { - let mut base_adjustment = - match self.fcx.inh.adjustments.borrow().get(&base_expr.id) { - Some(&ty::AdjustDerefRef(ref adr)) => (*adr).clone(), - None => ty::AutoDerefRef { autoderefs: 0, autoref: None }, - Some(_) => { - self.tcx().sess.span_bug( - base_expr.span, - "unexpected adjustment type"); - } - }; - // If this is an overloaded index, the // adjustment will include an extra layer of // autoref because the method is an &self/&mut @@ -548,21 +525,44 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { // expects. This is annoying and horrible. We // ought to recode this routine so it doesn't // (ab)use the normal type checking paths. - base_adjustment.autoref = match base_adjustment.autoref { - None => { None } - Some(ty::AutoPtr(_, _, None)) => { None } - Some(ty::AutoPtr(_, _, Some(box r))) => { Some(r) } + let adj = self.fcx.inh.adjustments.borrow().get(&base_expr.id).cloned(); + let (autoderefs, unsize) = match adj { + Some(ty::AdjustDerefRef(adr)) => match adr.autoref { + None => { + assert!(adr.unsize.is_none()); + (adr.autoderefs, None) + } + Some(ty::AutoPtr(_, _)) => { + (adr.autoderefs, adr.unsize.map(|target| { + ty::deref(target, false) + .expect("fixup: AutoPtr is not &T").ty + })) + } + Some(_) => { + self.tcx().sess.span_bug( + base_expr.span, + &format!("unexpected adjustment autoref {}", + adr.repr(self.tcx()))); + } + }, + None => (0, None), Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment autoref"); + "unexpected adjustment type"); } }; - let adjusted_base_ty = - self.fcx.adjust_expr_ty( - &**base_expr, - Some(&ty::AdjustDerefRef(base_adjustment.clone()))); + let (adjusted_base_ty, unsize) = if let Some(target) = unsize { + (target, true) + } else { + (self.fcx.adjust_expr_ty(base_expr, + Some(&ty::AdjustDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: None + }))), false) + }; let index_expr_ty = self.fcx.expr_ty(&**index_expr); let result = check::try_index_step( @@ -571,7 +571,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { expr, &**base_expr, adjusted_base_ty, - base_adjustment, + autoderefs, + unsize, PreferMutLvalue, index_expr_ty); @@ -658,14 +659,3 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { self.span, infer::FnCall, value).0 } } - -fn wrap_autoref<'tcx, F>(mut deref: ty::AutoDerefRef<'tcx>, - base_fn: F) - -> ty::AutoDerefRef<'tcx> where - F: FnOnce(Option>>) -> ty::AutoRef<'tcx>, -{ - let autoref = mem::replace(&mut deref.autoref, None); - let autoref = autoref.map(|r| box r); - deref.autoref = Some(base_fn(autoref)); - deref -} diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 677ab56852..f1a4dbf7cd 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -122,8 +122,7 @@ pub fn lookup_in_trait<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Option> { lookup_in_trait_adjusted(fcx, span, self_expr, m_name, trait_def_id, - ty::AutoDerefRef { autoderefs: 0, autoref: None }, - self_ty, opt_input_types) + 0, false, self_ty, opt_input_types) } /// `lookup_in_trait_adjusted` is used for overloaded operators. It does a very narrow slice of @@ -140,7 +139,8 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, self_expr: Option<&ast::Expr>, m_name: ast::Name, trait_def_id: DefId, - autoderefref: ty::AutoDerefRef<'tcx>, + autoderefs: usize, + unsize: bool, self_ty: Ty<'tcx>, opt_input_types: Option>>) -> Option> @@ -241,18 +241,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(self_expr) => { debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, base adjustment={:?}, explicit_self={:?})", - self_expr.id, autoderefref, method_ty.explicit_self); + (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", + self_expr.id, autoderefs, unsize, + method_ty.explicit_self); match method_ty.explicit_self { ty::ByValueExplicitSelfCategory => { // Trait method is fn(self), no transformation needed. - if !autoderefref.is_identity() { - fcx.write_adjustment( - self_expr.id, - span, - ty::AdjustDerefRef(autoderefref)); - } + assert!(!unsize); + fcx.write_autoderef_adjustment(self_expr.id, autoderefs); } ty::ByReferenceExplicitSelfCategory(..) => { @@ -260,14 +257,15 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // autoref. Pull the region etc out of the type of first argument. match transformed_self_ty.sty { ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => { - let ty::AutoDerefRef { autoderefs, autoref } = autoderefref; - let autoref = autoref.map(|r| box r); - fcx.write_adjustment( - self_expr.id, - span, + fcx.write_adjustment(self_expr.id, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoPtr(*region, mutbl, autoref)) + autoref: Some(ty::AutoPtr(region, mutbl)), + unsize: if unsize { + Some(transformed_self_ty) + } else { + None + } })); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 41eae88158..08e2f47c5a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -31,7 +31,6 @@ use std::rc::Rc; use util::ppaux::Repr; use self::CandidateKind::*; -pub use self::PickAdjustment::*; pub use self::PickKind::*; struct ProbeContext<'a, 'tcx:'a> { @@ -49,7 +48,8 @@ struct ProbeContext<'a, 'tcx:'a> { struct CandidateStep<'tcx> { self_ty: Ty<'tcx>, - adjustment: PickAdjustment, + autoderefs: usize, + unsize: bool } struct Candidate<'tcx> { @@ -70,8 +70,24 @@ enum CandidateKind<'tcx> { pub struct Pick<'tcx> { pub method_ty: Rc>, - pub adjustment: PickAdjustment, pub kind: PickKind<'tcx>, + + // Indicates that the source expression should be autoderef'd N times + // + // A = expr | *expr | **expr | ... + pub autoderefs: usize, + + // Indicates that an autoref is applied after the optional autoderefs + // + // B = A | &A | &mut A + pub autoref: Option, + + // Indicates that the source expression should be "unsized" to a + // target type. This should probably eventually go away in favor + // of just coercing method receivers. + // + // C = B | unsize(B) + pub unsize: Option>, } #[derive(Clone,Debug)] @@ -85,30 +101,6 @@ pub enum PickKind<'tcx> { pub type PickResult<'tcx> = Result, MethodError>; -// This is a kind of "abstracted" version of ty::AutoAdjustment. The -// difference is that it doesn't embed any regions or other -// specifics. The "confirmation" step recreates those details as -// needed. -#[derive(Clone,Debug)] -pub enum PickAdjustment { - // Indicates that the source expression should be autoderef'd N times - // - // A = expr | *expr | **expr - AutoDeref(usize), - - // Indicates that the source expression should be autoderef'd N - // times and then "unsized". This should probably eventually go - // away in favor of just coercing method receivers. - // - // A = unsize(expr | *expr | **expr) - AutoUnsizeLength(/* number of autoderefs */ usize, /* length*/ usize), - - // Indicates that an autoref is applied after some number of other adjustments - // - // A = &A | &mut A - AutoRef(ast::Mutability, Box), -} - #[derive(PartialEq, Eq, Copy, Clone)] pub enum Mode { // An expression of the form `receiver.method_name(...)`. @@ -149,7 +141,8 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } else { vec![CandidateStep { self_ty: self_ty, - adjustment: AutoDeref(0) + autoderefs: 0, + unsize: false }] }; @@ -200,16 +193,21 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, NoPreference, |t, d| { - let adjustment = AutoDeref(d); - steps.push(CandidateStep { self_ty: t, adjustment: adjustment }); + steps.push(CandidateStep { + self_ty: t, + autoderefs: d, + unsize: false + }); None::<()> // keep iterating until we can't anymore }); match final_ty.sty { - ty::ty_vec(elem_ty, Some(len)) => { + ty::ty_vec(elem_ty, Some(_)) => { + let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None); steps.push(CandidateStep { - self_ty: ty::mk_vec(fcx.tcx(), elem_ty, None), - adjustment: AutoUnsizeLength(dereferences, len), + self_ty: slice_ty, + autoderefs: dereferences, + unsize: true }); } ty::ty_err => return None, @@ -926,20 +924,21 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { * consuming them for their entire lifetime. */ - let adjustment = match step.adjustment { - AutoDeref(d) => consider_reborrow(step.self_ty, d), - AutoUnsizeLength(..) | AutoRef(..) => step.adjustment.clone(), - }; + if step.unsize { + return None; + } - return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone())); + self.pick_method(step.self_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; - fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: usize) -> PickAdjustment { // Insert a `&*` or `&mut *` if this is a reference type: - match ty.sty { - ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)), - _ => AutoDeref(d), + if let ty::ty_rptr(_, mt) = step.self_ty.sty { + pick.autoderefs += 1; + pick.autoref = Some(mt.mutbl); } - } + + pick + })) } fn pick_autorefd_method(&mut self, @@ -947,46 +946,28 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { -> Option> { let tcx = self.tcx(); - self.search_mutabilities( - |m| AutoRef(m, box step.adjustment.clone()), - |m,r| ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty:step.self_ty, mutbl:m})) - } - fn search_mutabilities(&mut self, - mut mk_adjustment: F, - mut mk_autoref_ty: G) - -> Option> where - F: FnMut(ast::Mutability) -> PickAdjustment, - G: FnMut(ast::Mutability, ty::Region) -> Ty<'tcx>, - { // In general, during probing we erase regions. See // `impl_self_ty()` for an explanation. - let region = ty::ReStatic; + let region = tcx.mk_region(ty::ReStatic); // Search through mutabilities in order to find one where pick works: - [ast::MutImmutable, ast::MutMutable] - .iter() - .flat_map(|&m| { - let autoref_ty = mk_autoref_ty(m, region); - self.pick_method(autoref_ty) - .map(|r| self.adjust(r, mk_adjustment(m))) - .into_iter() - }) - .nth(0) - } - - fn adjust(&mut self, - result: PickResult<'tcx>, - adjustment: PickAdjustment) - -> PickResult<'tcx> - { - match result { - Err(e) => Err(e), - Ok(mut pick) => { - pick.adjustment = adjustment; - Ok(pick) - } - } + [ast::MutImmutable, ast::MutMutable].iter().filter_map(|&m| { + let autoref_ty = ty::mk_rptr(tcx, region, ty::mt { + ty: step.self_ty, + mutbl: m + }); + self.pick_method(autoref_ty).map(|r| r.map(|mut pick| { + pick.autoderefs = step.autoderefs; + pick.autoref = Some(m); + pick.unsize = if step.unsize { + Some(step.self_ty) + } else { + None + }; + pick + })) + }).nth(0) } fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option> { @@ -1122,8 +1103,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { let method_ty = probes[0].method_ty.clone(); Some(Pick { method_ty: method_ty, - adjustment: AutoDeref(0), - kind: TraitPick(trait_def_id, method_num) + kind: TraitPick(trait_def_id, method_num), + autoderefs: 0, + autoref: None, + unsize: None }) } @@ -1296,7 +1279,6 @@ impl<'tcx> Candidate<'tcx> { fn to_unadjusted_pick(&self) -> Pick<'tcx> { Pick { method_ty: self.method_ty.clone(), - adjustment: AutoDeref(0), kind: match self.kind { InherentImplCandidate(def_id, _) => { InherentImplPick(def_id) @@ -1323,7 +1305,10 @@ impl<'tcx> Candidate<'tcx> { ProjectionCandidate(def_id, index) => { TraitPick(def_id, index) } - } + }, + autoderefs: 0, + autoref: None, + unsize: None } } @@ -1392,15 +1377,10 @@ impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("CandidateStep({},{:?})", + format!("CandidateStep({}, autoderefs={}, unsize={})", self.self_ty.repr(tcx), - self.adjustment) - } -} - -impl<'tcx> Repr<'tcx> for PickAdjustment { - fn repr(&self, _tcx: &ty::ctxt) -> String { - format!("{:?}", self) + self.autoderefs, + self.unsize) } } @@ -1412,9 +1392,12 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> { impl<'tcx> Repr<'tcx> for Pick<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { - format!("Pick(method_ty={}, adjustment={:?}, kind={:?})", + format!("Pick(method_ty={}, autoderefs={}, + autoref={}, unsize={}, kind={:?})", self.method_ty.repr(tcx), - self.adjustment, + self.autoderefs, + self.autoref.repr(tcx), + self.unsize.repr(tcx), self.kind) } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index c5ff8a14bc..a4175fe832 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -67,7 +67,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - if static_sources.len() > 0 { + if !static_sources.is_empty() { fcx.tcx().sess.fileline_note( span, "found defined static methods, maybe a `self` is missing?"); @@ -200,7 +200,7 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }) .collect::>(); - if candidates.len() > 0 { + if !candidates.is_empty() { // sort from most relevant to least relevant candidates.sort_by(|a, b| a.cmp(b).reverse()); candidates.dedup(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 156fbfede9..bff8e002a0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -139,6 +139,7 @@ pub mod demand; pub mod method; mod upvar; pub mod wf; +mod cast; mod closure; mod callee; mod compare_method; @@ -185,7 +186,7 @@ pub struct Inherited<'a, 'tcx: 'a> { // back and process them. deferred_call_resolutions: RefCell>>>, - deferred_cast_checks: RefCell>>, + deferred_cast_checks: RefCell>>, } trait DeferredCallResolution<'tcx> { @@ -194,15 +195,6 @@ trait DeferredCallResolution<'tcx> { type DeferredCallResolutionHandler<'tcx> = Box+'tcx>; -/// Reifies a cast check to be checked once we have full type information for -/// a function context. -struct CastCheck<'tcx> { - expr: ast::Expr, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - span: Span, -} - /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. #[derive(Copy, Clone)] @@ -449,10 +441,11 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>) } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } +struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> } impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &'tcx ast::Item) { - check_item(self.ccx, i); + check_item_type(self.ccx, i); visit::walk_item(self, i); } @@ -468,6 +461,13 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> { } } +impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { + fn visit_item(&mut self, i: &'tcx ast::Item) { + check_item_body(self.ccx, i); + visit::walk_item(self, i); + } +} + pub fn check_item_types(ccx: &CrateCtxt) { let krate = ccx.tcx.map.krate(); let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); @@ -482,6 +482,11 @@ pub fn check_item_types(ccx: &CrateCtxt) { ccx.tcx.sess.abort_if_errors(); + let mut visit = CheckItemBodiesVisitor { ccx: ccx }; + visit::walk_crate(&mut visit, krate); + + ccx.tcx.sess.abort_if_errors(); + for drop_method_did in ccx.tcx.destructors.borrow().iter() { if drop_method_did.krate == ast::LOCAL_CRATE { let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node); @@ -721,13 +726,13 @@ pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) { } } -pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { - debug!("check_item(it.id={}, it.ident={})", +pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { + debug!("check_item_type(it.id={}, it.ident={})", it.id, ty::item_path_str(ccx.tcx, local_def(it.id))); let _indenter = indenter(); - match it.node { + // Consts can play a role in type-checking, so they are included here. ast::ItemStatic(_, _, ref e) | ast::ItemConst(_, ref e) => check_const(ccx, it.span, &**e, it.id), ast::ItemEnum(ref enum_definition, _) => { @@ -736,16 +741,9 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { &enum_definition.variants, it.id); } - ast::ItemFn(ref decl, _, _, _, ref body) => { - let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); - check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); - } + ast::ItemFn(_, _, _, _, _) => {} // entirely within check_item_body ast::ItemImpl(_, _, _, _, _, ref impl_items) => { - debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); - - let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); - + debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) { Some(impl_trait_ref) => { check_impl_items_against_trait(ccx, @@ -755,39 +753,9 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } None => { } } - - for impl_item in impl_items { - match impl_item.node { - ast::MethodImplItem(ref sig, ref body) => { - check_method_body(ccx, &impl_pty.generics, sig, body, - impl_item.id, impl_item.span); - } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => { - // Nothing to do here. - } - } - } - } - ast::ItemTrait(_, ref generics, _, ref trait_items) => { + ast::ItemTrait(_, ref generics, _, _) => { check_trait_on_unimplemented(ccx, generics, it); - let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); - for trait_item in trait_items { - match trait_item.node { - ast::MethodTraitItem(_, None) => { - // Nothing to do, since required methods don't have - // bodies to check. - } - ast::MethodTraitItem(ref sig, Some(ref body)) => { - check_method_body(ccx, &trait_def.generics, sig, body, - trait_item.id, trait_item.span); - } - ast::TypeTraitItem(..) => { - // Nothing to do. - } - } - } } ast::ItemStruct(..) => { check_struct(ccx, it.id, it.span); @@ -822,6 +790,57 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { } } +pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { + debug!("check_item_body(it.id={}, it.ident={})", + it.id, + ty::item_path_str(ccx.tcx, local_def(it.id))); + let _indenter = indenter(); + match it.node { + ast::ItemFn(ref decl, _, _, _, ref body) => { + let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); + check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); + } + ast::ItemImpl(_, _, _, _, _, ref impl_items) => { + debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id); + + let impl_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); + + for impl_item in impl_items { + match impl_item.node { + ast::MethodImplItem(ref sig, ref body) => { + check_method_body(ccx, &impl_pty.generics, sig, body, + impl_item.id, impl_item.span); + } + ast::TypeImplItem(_) | + ast::MacImplItem(_) => { + // Nothing to do here. + } + } + } + } + ast::ItemTrait(_, _, _, ref trait_items) => { + let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id)); + for trait_item in trait_items { + match trait_item.node { + ast::MethodTraitItem(_, None) => { + // Nothing to do, since required methods don't have + // bodies to check. + } + ast::MethodTraitItem(ref sig, Some(ref body)) => { + check_method_body(ccx, &trait_def.generics, sig, body, + trait_item.id, trait_item.span); + } + ast::TypeTraitItem(..) => { + // Nothing to do. + } + } + } + } + _ => {/* nothing to do */ } + } +} + fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics: &ast::Generics, item: &ast::Item) { @@ -1071,141 +1090,6 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } -fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { - fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - t_1: Ty<'tcx>, - t_e: Ty<'tcx>) { - fcx.type_error_message(span, |actual| { - format!("illegal cast; cast through an \ - integer first: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); - } - - let span = cast.span; - let e = &cast.expr; - let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); - let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); - - // Check for trivial casts. - if !ty::type_has_ty_infer(t_1) { - if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { - if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, - e.id, - span, - format!("trivial numeric cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); - } else { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, - e.id, - span, - format!("trivial cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); - } - return; - } - } - - let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e); - let t_e_is_scalar = ty::type_is_scalar(t_e); - let t_e_is_integral = ty::type_is_integral(t_e); - let t_e_is_float = ty::type_is_floating_point(t_e); - let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); - - let t_1_is_scalar = ty::type_is_scalar(t_1); - let t_1_is_char = ty::type_is_char(t_1); - let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); - let t_1_is_float = ty::type_is_floating_point(t_1); - - // casts to scalars other than `char` and `bare fn` are trivial - let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; - - if t_e_is_bare_fn_item && t_1_is_bare_fn { - demand::coerce(fcx, e.span, t_1, &e); - } else if t_1_is_char { - let t_e = fcx.infcx().shallow_resolve(t_e); - if t_e.sty != ty::ty_uint(ast::TyU8) { - fcx.type_error_message(span, |actual| { - format!("only `u8` can be cast as `char`, not `{}`", actual) - }, t_e, None); - } - } else if t_1.sty == ty::ty_bool { - span_err!(fcx.tcx().sess, span, E0054, - "cannot cast as `bool`, compare with zero instead"); - } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !( - t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) { - // Casts to float must go through an integer or boolean - cast_through_integer_err(fcx, span, t_1, t_e) - } else if t_e_is_c_enum && t_1_is_trivial { - if ty::type_is_unsafe_ptr(t_1) { - // ... and likewise with C enum -> *T - cast_through_integer_err(fcx, span, t_1, t_e) - } - // casts from C-like enums are allowed - } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) { - fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool { - match t1.sty { - ty::ty_vec(_, Some(_)) => {} - _ => return false - } - if ty::type_needs_infer(t2) { - // This prevents this special case from going off when casting - // to a type that isn't fully specified; e.g. `as *_`. (Issue - // #14893.) - return false - } - - let el = ty::sequence_element_type(fcx.tcx(), t1); - infer::mk_eqty(fcx.infcx(), - false, - infer::Misc(sp), - el, - t2).is_ok() - } - - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow unsafe pointers to work correctly, we - // need to special-case obtaining an unsafe pointer - // from a region pointer to a vector. - - /* this cast is only allowed from &[T, ..n] to *T or - &T to *T. */ - match (&t_e.sty, &t_1.sty) { - (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }), - &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable })) - if types_compatible(fcx, e.span, mt1, mt2) => { - /* this case is allowed */ - } - _ => { - demand::coerce(fcx, e.span, t_1, &e); - } - } - } else if !(t_e_is_scalar && t_1_is_trivial) { - /* - If more type combinations should be supported than are - supported here, then file an enhancement issue and - record the issue number in this comment. - */ - fcx.type_error_message(span, |actual| { - format!("non-scalar cast: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); - } -} - impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx } @@ -1435,21 +1319,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_autoderef_adjustment(&self, node_id: ast::NodeId, - span: Span, derefs: usize) { - if derefs == 0 { return; } self.write_adjustment( node_id, - span, ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: derefs, - autoref: None }) + autoref: None, + unsize: None + }) ); } pub fn write_adjustment(&self, node_id: ast::NodeId, - span: Span, adj: ty::AutoAdjustment<'tcx>) { debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx())); @@ -1457,13 +1339,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - // Careful: adjustments can imply trait obligations if we are - // casting from a concrete type to an object type. I think - // it'd probably be nicer to move the logic that creates the - // obligation into the code that creates the adjustment, but - // that's a bit awkward, so instead we go digging and pull the - // obligation out here. - self.register_adjustment_obligations(span, &adj); self.inh.adjustments.borrow_mut().insert(node_id, adj); } @@ -1526,74 +1401,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause) } - fn register_adjustment_obligations(&self, - span: Span, - adj: &ty::AutoAdjustment<'tcx>) { - match *adj { - ty::AdjustReifyFnPointer(..) => { } - ty::AdjustUnsafeFnPointer => { } - ty::AdjustDerefRef(ref d_r) => { - match d_r.autoref { - Some(ref a_r) => { - self.register_autoref_obligations(span, a_r); - } - None => {} - } - } - } - } - - fn register_autoref_obligations(&self, - span: Span, - autoref: &ty::AutoRef<'tcx>) { - match *autoref { - ty::AutoUnsize(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } - ty::AutoPtr(_, _, None) | - ty::AutoUnsafe(_, None) => { - } - ty::AutoPtr(_, _, Some(ref a_r)) | - ty::AutoUnsafe(_, Some(ref a_r)) => { - self.register_autoref_obligations(span, &**a_r) - } - ty::AutoUnsizeUniq(ref unsize) => { - self.register_unsize_obligations(span, unsize); - } - } - } - - fn register_unsize_obligations(&self, - span: Span, - unsize: &ty::UnsizeKind<'tcx>) { - debug!("register_unsize_obligations: unsize={:?}", unsize); - - match *unsize { - ty::UnsizeLength(..) => {} - ty::UnsizeStruct(ref u, _) => { - self.register_unsize_obligations(span, &**u) - } - ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable::check_object_safety(self.tcx(), ty_trait, span); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` implements `Foo`: - vtable::register_object_cast_obligations(self, - span, - ty_trait, - self_ty); - - // If the type is `Foo+'a`, ensures that the type - // being cast to `Foo+'a` outlives `'a`: - let cause = traits::ObligationCause { span: span, - body_id: self.body_id, - code: traits::ObjectCastObligation(self_ty) }; - self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause); - } - ty::UnsizeUpcast(_) => { } - } - } - /// Returns the type of `def_id` with all generics replaced by by fresh type/region variables. /// Also returns the substitution from the type parameters on `def_id` to the fresh variables. /// Registers any trait obligations specified on `def_id` at the same time. @@ -1702,6 +1509,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span) } + pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool { + if let Some(mt) = ty::deref(ty, true) { + return !self.type_is_known_to_be_sized(mt.ty, span); + } + false + } + pub fn register_builtin_bound(&self, ty: Ty<'tcx>, builtin_bound: ty::BuiltinBound, @@ -1925,7 +1739,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_casts(&self) { let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); for check in deferred_cast_checks.iter() { - check_cast(self, check); + cast::check_cast(self, check); } deferred_cast_checks.clear(); @@ -2017,7 +1831,8 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, let mt = match ty::deref(resolved_t, false) { Some(mt) => Some(mt), None => { - let method_call = opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs)); + let method_call = + opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32)); // Super subtle: it might seem as though we should // pass `opt_expr` to `try_overloaded_deref`, so that @@ -2108,13 +1923,13 @@ fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } -fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, - base_expr: &ast::Expr, - base_ty: Ty<'tcx>, - lvalue_pref: LvaluePreference, - mut step: F) - -> Option where - F: FnMut(Ty<'tcx>, ty::AutoDerefRef<'tcx>) -> Option, +fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &ast::Expr, + base_expr: &'tcx ast::Expr, + base_ty: Ty<'tcx>, + idx_ty: Ty<'tcx>, + lvalue_pref: LvaluePreference) + -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the // autoderef that normal method probing does. They could likely be @@ -2127,9 +1942,9 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, lvalue_pref, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - step(adj_ty, autoderefref) - }); + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adj_ty, idx, false, lvalue_pref, idx_ty) + }); if final_mt.is_some() { return final_mt; @@ -2137,41 +1952,38 @@ fn autoderef_for_index<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // After we have fully autoderef'd, if the resulting type is [T, ..n], then // do a final unsized coercion to yield [T]. - match ty.sty { - ty::ty_vec(element_ty, Some(n)) => { - let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); - let autoderefref = ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoUnsize(ty::UnsizeLength(n))) - }; - step(adjusted_ty, autoderefref) - } - _ => { - None - } + if let ty::ty_vec(element_ty, Some(_)) = ty.sty { + let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None); + try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr, + adjusted_ty, autoderefs, true, lvalue_pref, idx_ty) + } else { + None } } /// To type-check `base_expr[index_expr]`, we progressively autoderef (and otherwise adjust) /// `base_expr`, looking for a type which either supports builtin indexing or overloaded indexing. /// This loop implements one step in that search; the autoderef loop is implemented by -/// `autoderef_for_index`. +/// `lookup_indexing`. fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_call: MethodCall, expr: &ast::Expr, base_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - adjustment: ty::AutoDerefRef<'tcx>, + autoderefs: usize, + unsize: bool, lvalue_pref: LvaluePreference, index_ty: Ty<'tcx>) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let tcx = fcx.tcx(); - debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, adjustment={:?}, index_ty={})", + debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \ + autoderefs={}, unsize={}, index_ty={})", expr.repr(tcx), base_expr.repr(tcx), adjusted_ty.repr(tcx), - adjustment, + autoderefs, + unsize, index_ty.repr(tcx)); let input_ty = fcx.infcx().next_ty_var(); @@ -2180,7 +1992,9 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match (ty::index(adjusted_ty), &index_ty.sty) { (Some(ty), &ty::ty_uint(ast::TyUs)) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => { debug!("try_index_step: success, using built-in indexing"); - fcx.write_adjustment(base_expr.id, base_expr.span, ty::AdjustDerefRef(adjustment)); + // If we had `[T; N]`, we should've caught it before unsizing to `[T]`. + assert!(!unsize); + fcx.write_autoderef_adjustment(base_expr.id, autoderefs); return Some((tcx.types.usize, ty)); } _ => {} @@ -2194,7 +2008,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*base_expr), token::intern("index_mut"), trait_did, - adjustment.clone(), + autoderefs, + unsize, adjusted_ty, Some(vec![input_ty])) } @@ -2209,7 +2024,8 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Some(&*base_expr), token::intern("index"), trait_did, - adjustment.clone(), + autoderefs, + unsize, adjusted_ty, Some(vec![input_ty])) } @@ -2798,7 +2614,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); + fcx.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} @@ -2827,8 +2643,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, actual) }, expr_t, None); - if let Some(t) = ty::ty_to_def_id(expr_t) { - suggest_field_names(t, field, tcx, vec![]); + if let ty::ty_struct(did, _) = expr_t.sty { + suggest_field_names(did, field, tcx, vec![]); } } @@ -2909,7 +2725,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match field_ty { Some(field_ty) => { fcx.write_ty(expr.id, field_ty); - fcx.write_autoderef_adjustment(base.id, base.span, autoderefs); + fcx.write_autoderef_adjustment(base.id, autoderefs); return; } None => {} @@ -3341,11 +3157,17 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def = path_res.base_def; if path_res.depth == 0 { - let (scheme, predicates) = - type_scheme_and_predicates_for_def(fcx, expr.span, def); - instantiate_path(fcx, &path.segments, - scheme, &predicates, - opt_self_ty, def, expr.span, id); + let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, + expr.span, + def); + instantiate_path(fcx, + &path.segments, + scheme, + &predicates, + opt_self_ty, + def, + expr.span, + id); } else { let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; @@ -3531,12 +3353,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - deferred_cast_checks.push(CastCheck { - expr: (**e).clone(), - expr_ty: t_e, - cast_ty: t_1, - span: expr.span, - }); + let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span); + deferred_cast_checks.push(cast_check); } } ast::ExprVec(ref args) => { @@ -3709,7 +3527,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, .ty_to_string( actual_structure_type), type_error_description); - ty::note_and_explain_type_err(tcx, &type_error); + ty::note_and_explain_type_err(tcx, &type_error, path.span); } } } @@ -3734,26 +3552,13 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, fcx.write_ty(id, idx_t); } else { let base_t = structurally_resolved_type(fcx, expr.span, base_t); - - let result = - autoderef_for_index(fcx, &**base, base_t, lvalue_pref, |adj_ty, adj| { - try_index_step(fcx, - MethodCall::expr(expr.id), - expr, - &**base, - adj_ty, - adj, - lvalue_pref, - idx_t) - }); - - match result { + match lookup_indexing(fcx, expr, base, base_t, idx_t, lvalue_pref) { Some((index_ty, element_ty)) => { let idx_expr_ty = fcx.expr_ty(idx); demand::eqtype(fcx, expr.span, index_ty, idx_expr_ty); fcx.write_ty(id, element_ty); } - _ => { + None => { check_expr_has_type(fcx, &**idx, fcx.tcx().types.err); fcx.type_error_message( expr.span, @@ -4480,7 +4285,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // // The first step then is to categorize the segments appropriately. - assert!(segments.len() >= 1); + assert!(!segments.is_empty()); let mut ufcs_method = None; let mut segment_spaces: Vec<_>; @@ -4702,7 +4507,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - if data.bindings.len() > 0 { + if !data.bindings.is_empty() { span_err!(fcx.tcx().sess, data.bindings[0].span, E0182, "unexpected binding of associated item in expression path \ (only allowed in type paths)"); @@ -4941,7 +4746,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tps.len(), ppaux::ty_to_string(ccx.tcx, ty)); // make a vector of booleans initially false, set to true when used - if tps.len() == 0 { return; } + if tps.is_empty() { return; } let mut tps_used: Vec<_> = repeat(false).take(tps.len()).collect(); ty::walk_ty(ty, |t| { @@ -5207,6 +5012,12 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { "assume" => (0, vec![tcx.types.bool], ty::mk_nil(tcx)), + "discriminant_value" => (1, vec![ + ty::mk_imm_rptr(tcx, + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), + ty::BrAnon(0))), + param(ccx, 0))], tcx.types.u64), + ref other => { span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", *other); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 49e88dc148..b4000788d1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -20,7 +20,6 @@ use super::{ PreferMutLvalue, structurally_resolved_type, }; -use middle::infer; use middle::traits; use middle::ty::{self, Ty}; use syntax::ast; @@ -314,36 +313,15 @@ fn lookup_op_method<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, let method = match trait_did { Some(trait_did) => { - // We do eager coercions to make using operators - // more ergonomic: - // - // - If the input is of type &'a T (resp. &'a mut T), - // then reborrow it to &'b T (resp. &'b mut T) where - // 'b <= 'a. This makes things like `x == y`, where - // `x` and `y` are both region pointers, work. We - // could also solve this with variance or different - // traits that don't force left and right to have same - // type. - let (adj_ty, adjustment) = match lhs_ty.sty { - ty::ty_rptr(r_in, mt) => { - let r_adj = fcx.infcx().next_region_var(infer::Autoref(lhs_expr.span)); - fcx.mk_subr(infer::Reborrow(lhs_expr.span), r_adj, *r_in); - let adjusted_ty = ty::mk_rptr(fcx.tcx(), fcx.tcx().mk_region(r_adj), mt); - let autoptr = ty::AutoPtr(r_adj, mt.mutbl, None); - let adjustment = ty::AutoDerefRef { autoderefs: 1, autoref: Some(autoptr) }; - (adjusted_ty, adjustment) - } - _ => { - (lhs_ty, ty::AutoDerefRef { autoderefs: 0, autoref: None }) - } - }; - - debug!("adjusted_ty={} adjustment={:?}", - adj_ty.repr(fcx.tcx()), - adjustment); - - method::lookup_in_trait_adjusted(fcx, expr.span, Some(lhs_expr), opname, - trait_did, adjustment, adj_ty, Some(other_tys)) + method::lookup_in_trait_adjusted(fcx, + expr.span, + Some(lhs_expr), + opname, + trait_did, + 0, + false, + lhs_ty, + Some(other_tys)) } None => None }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 9171367468..6dfc1e0ea6 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -499,10 +499,10 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { if let Some(adjustment) = rcx.fcx.inh.adjustments.borrow().get(&expr.id) { debug!("adjustment={:?}", adjustment); match *adjustment { - ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => { + ty::AdjustDerefRef(ty::AutoDerefRef {autoderefs, ref autoref, ..}) => { let expr_ty = rcx.resolve_node_type(expr.id); constrain_autoderefs(rcx, expr, autoderefs, expr_ty); - if let Some(ref autoref) = *opt_autoref { + if let Some(ref autoref) = *autoref { link_autoref(rcx, expr, autoderefs, autoref); // Require that the resulting region encompasses @@ -872,7 +872,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id)); for i in 0..derefs { - let method_call = MethodCall::autoderef(deref_expr.id, i); + let method_call = MethodCall::autoderef(deref_expr.id, i as u32); debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs); derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) { @@ -904,7 +904,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i)); debug!("constrain_autoderefs: self_cmt={:?}", self_cmt.repr(rcx.tcx())); - link_region(rcx, deref_expr.span, *r, + link_region(rcx, deref_expr.span, r, ty::BorrowKind::from_mutbl(m), self_cmt); } @@ -1102,7 +1102,7 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, ast::PatVec(_, Some(ref slice_pat), _) => { match mc.cat_slice_pattern(sub_cmt, &**slice_pat) { Ok((slice_cmt, slice_mutbl, slice_r)) => { - link_region(rcx, sub_pat.span, slice_r, + link_region(rcx, sub_pat.span, &slice_r, ty::BorrowKind::from_mutbl(slice_mutbl), slice_cmt); } @@ -1119,20 +1119,23 @@ fn link_pattern<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, fn link_autoref(rcx: &Rcx, expr: &ast::Expr, autoderefs: usize, - autoref: &ty::AutoRef) { - + autoref: &ty::AutoRef) +{ debug!("link_autoref(autoref={:?})", autoref); let mc = mc::MemCategorizationContext::new(rcx.fcx); let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs)); debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx())); match *autoref { - ty::AutoPtr(r, m, _) => { + ty::AutoPtr(r, m) => { link_region(rcx, expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(..) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} + ty::AutoUnsafe(m) => { + let r = ty::ReScope(CodeExtent::from_node_id(expr.id)); + link_region(rcx, expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt); + } } } @@ -1147,7 +1150,7 @@ fn link_by_ref(rcx: &Rcx, let mc = mc::MemCategorizationContext::new(rcx.fcx); let expr_cmt = ignore_err!(mc.cat_expr(expr)); let borrow_region = ty::ReScope(callee_scope); - link_region(rcx, expr.span, borrow_region, ty::ImmBorrow, expr_cmt); + link_region(rcx, expr.span, &borrow_region, ty::ImmBorrow, expr_cmt); } /// Like `link_region()`, except that the region is extracted from the type of `id`, which must be @@ -1165,7 +1168,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); - link_region(rcx, span, r, ty::BorrowKind::from_mutbl(mutbl), + link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } } @@ -1175,7 +1178,7 @@ fn link_region_from_node_type<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, /// between regions, as explained in `link_reborrowed_region()`. fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, borrow_cmt: mc::cmt<'tcx>) { let mut borrow_cmt = borrow_cmt; @@ -1269,7 +1272,7 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, /// recurse and process `ref_cmt` (see case 2 above). fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, span: Span, - borrow_region: ty::Region, + borrow_region: &ty::Region, borrow_kind: ty::BorrowKind, ref_cmt: mc::cmt<'tcx>, ref_region: ty::Region, @@ -1314,7 +1317,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, debug!("link_reborrowed_region: {} <= {}", borrow_region.repr(rcx.tcx()), ref_region.repr(rcx.tcx())); - rcx.fcx.mk_subr(cause, borrow_region, ref_region); + rcx.fcx.mk_subr(cause, *borrow_region, ref_region); // If we end up needing to recurse and establish a region link // with `ref_cmt`, calculate what borrow kind we will end up diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 63c34b65d7..a9094fce57 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -13,9 +13,7 @@ use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode}; use middle::traits::{Obligation, ObligationCause}; use middle::traits::report_fulfillment_errors; use middle::ty::{self, Ty, AsPredicate}; -use syntax::ast; use syntax::codemap::Span; -use util::nodemap::FnvHashSet; use util::ppaux::{Repr, UserString}; @@ -133,46 +131,9 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fcx.register_predicate(projection_obligation); } - // Finally, check that there IS a projection predicate for every associated type. - check_object_type_binds_all_associated_types(fcx.tcx(), - span, - object_trait); - object_trait_ref } -fn check_object_type_binds_all_associated_types<'tcx>(tcx: &ty::ctxt<'tcx>, - span: Span, - object_trait: &ty::TyTrait<'tcx>) -{ - let object_trait_ref = - object_trait.principal_trait_ref_with_self_ty(tcx, tcx.types.err); - - let mut associated_types: FnvHashSet<(ast::DefId, ast::Name)> = - traits::supertraits(tcx, object_trait_ref.clone()) - .flat_map(|tr| { - let trait_def = ty::lookup_trait_def(tcx, tr.def_id()); - trait_def.associated_type_names - .clone() - .into_iter() - .map(move |associated_type_name| (tr.def_id(), associated_type_name)) - }) - .collect(); - - for projection_bound in &object_trait.bounds.projection_bounds { - let pair = (projection_bound.0.projection_ty.trait_ref.def_id, - projection_bound.0.projection_ty.item_name); - associated_types.remove(&pair); - } - - for (trait_def_id, name) in associated_types { - span_err!(tcx.sess, span, E0191, - "the value of the associated type `{}` (from the trait `{}`) must be specified", - name.user_string(tcx), - ty::item_path_str(tcx, trait_def_id)); - } -} - pub fn select_all_fcx_obligations_and_apply_defaults(fcx: &FnCtxt) { debug!("select_all_fcx_obligations_and_apply_defaults"); diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index a86e2b17c9..83e0c39859 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -10,7 +10,7 @@ use astconv::AstConv; use check::{FnCtxt, Inherited, blank_fn_ctxt, vtable, regionck}; -use constrained_type_params::identify_constrained_type_params; +use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::region; use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; @@ -117,15 +117,10 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_variances_for_type_defn(item, ast_generics); } - ast::ItemTrait(_, ref ast_generics, _, ref items) => { + ast::ItemTrait(_, _, _, ref items) => { let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(item.id)); - reject_non_type_param_bounds( - ccx.tcx, - item.span, - &trait_predicates); - self.check_variances(item, ast_generics, &trait_predicates, - self.tcx().lang_items.phantom_fn()); + reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) { if !items.is_empty() { ccx.tcx.sess.span_err( @@ -179,7 +174,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } // For DST, all intermediate types must be sized. - if variant.fields.len() > 0 { + if !variant.fields.is_empty() { for field in variant.fields.init() { fcx.register_builtin_bound( field.ty, @@ -287,38 +282,16 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { ast_generics: &ast::Generics) { let item_def_id = local_def(item.id); - let predicates = ty::lookup_predicates(self.tcx(), item_def_id); - self.check_variances(item, - ast_generics, - &predicates, - self.tcx().lang_items.phantom_data()); - } - - fn check_variances(&self, - item: &ast::Item, - ast_generics: &ast::Generics, - ty_predicates: &ty::GenericPredicates<'tcx>, - suggested_marker_id: Option) - { - let variance_lang_items = &[ - self.tcx().lang_items.phantom_fn(), - self.tcx().lang_items.phantom_data(), - ]; - - let item_def_id = local_def(item.id); - let is_lang_item = variance_lang_items.iter().any(|n| *n == Some(item_def_id)); - if is_lang_item { - return; - } - + let ty_predicates = ty::lookup_predicates(self.tcx(), item_def_id); let variances = ty::item_variances(self.tcx(), item_def_id); let mut constrained_parameters: HashSet<_> = variances.types - .iter_enumerated() - .filter(|&(_, _, &variance)| variance != ty::Bivariant) - .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) - .collect(); + .iter_enumerated() + .filter(|&(_, _, &variance)| variance != ty::Bivariant) + .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) + .map(|p| Parameter::Type(p)) + .collect(); identify_constrained_type_params(self.tcx(), ty_predicates.predicates.as_slice(), @@ -327,11 +300,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { for (space, index, _) in variances.types.iter_enumerated() { let param_ty = self.param_ty(ast_generics, space, index); - if constrained_parameters.contains(¶m_ty) { + if constrained_parameters.contains(&Parameter::Type(param_ty)) { continue; } let span = self.ty_param_span(ast_generics, item, space, index); - self.report_bivariance(span, param_ty.name, suggested_marker_id); + self.report_bivariance(span, param_ty.name); } for (space, index, &variance) in variances.regions.iter_enumerated() { @@ -342,7 +315,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { assert_eq!(space, TypeSpace); let span = ast_generics.lifetimes[index].lifetime.span; let name = ast_generics.lifetimes[index].lifetime.name; - self.report_bivariance(span, name, suggested_marker_id); + self.report_bivariance(span, name); } } @@ -377,14 +350,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn report_bivariance(&self, span: Span, - param_name: ast::Name, - suggested_marker_id: Option) + param_name: ast::Name) { self.tcx().sess.span_err( span, &format!("parameter `{}` is never used", param_name.user_string(self.tcx()))); + let suggested_marker_id = self.tcx().lang_items.phantom_data(); match suggested_marker_id { Some(def_id) => { self.tcx().sess.fileline_help( @@ -686,7 +659,7 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, enum_def.variants.iter() .map(|variant| { match variant.node.kind { - ast::TupleVariantKind(ref args) if args.len() > 0 => { + ast::TupleVariantKind(ref args) if !args.is_empty() => { let ctor_ty = ty::node_id_to_type(fcx.tcx(), variant.node.id); // the regions in the argument types come from the diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 37f4325248..f778a64f94 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -285,11 +285,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } Some(adjustment) => { - let adj_object = ty::adjust_is_object(&adjustment); let resolved_adjustment = match adjustment { - ty::AdjustReifyFnPointer(def_id) => { - ty::AdjustReifyFnPointer(def_id) - } + ty::AdjustReifyFnPointer => ty::AdjustReifyFnPointer, ty::AdjustUnsafeFnPointer => { ty::AdjustUnsafeFnPointer @@ -297,18 +294,14 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { ty::AdjustDerefRef(adj) => { for autoderef in 0..adj.autoderefs { - let method_call = MethodCall::autoderef(id, autoderef); - self.visit_method_map_entry(reason, method_call); - } - - if adj_object { - let method_call = MethodCall::autoobject(id); + let method_call = MethodCall::autoderef(id, autoderef as u32); self.visit_method_map_entry(reason, method_call); } ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs: adj.autoderefs, autoref: self.resolve(&adj.autoref, reason), + unsize: self.resolve(&adj.unsize, reason), }) } }; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 51d0c18872..b0c994f7f6 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -387,7 +387,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { for &impl_did in &*trait_impls.borrow() { let items = impl_items.get(&impl_did).unwrap(); - if items.len() < 1 { + if items.is_empty() { // We'll error out later. For now, just don't ICE. continue; } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index f8ca51b9e4..99b6d4154e 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -21,14 +21,14 @@ use syntax::ast_util; use syntax::visit; use syntax::codemap::Span; use util::nodemap::DefIdMap; -use util::ppaux::Repr; +use util::ppaux::{Repr, UserString}; pub fn check(tcx: &ty::ctxt) { let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() }; overlap.check_for_overlapping_impls(); - // this secondary walk specifically checks for impls of defaulted - // traits, for which additional overlap rules exist + // this secondary walk specifically checks for some other cases, + // like defaulted traits, for which additional overlap rules exist visit::walk_crate(&mut overlap, tcx.map.krate()); } @@ -153,7 +153,41 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { None => { } } } - _ => {} + ast::ItemImpl(_, _, _, Some(_), ref self_ty, _) => { + let impl_def_id = ast_util::local_def(item.id); + let trait_ref = ty::impl_trait_ref(self.tcx, impl_def_id).unwrap(); + let trait_def_id = trait_ref.def_id; + match trait_ref.self_ty().sty { + ty::ty_trait(ref data) => { + // This is something like impl Trait1 for Trait2. Illegal + // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. + + if !traits::is_object_safe(self.tcx, data.principal_def_id()) { + // this just means the self-ty is illegal, + // and probably this error should have + // been reported elsewhere, but I'm trying to avoid + // giving a misleading message below. + span_err!(self.tcx.sess, self_ty.span, E0372, + "the trait `{}` cannot be made into an object", + ty::item_path_str(self.tcx, data.principal_def_id())); + } else { + let mut supertrait_def_ids = + traits::supertrait_def_ids(self.tcx, data.principal_def_id()); + if supertrait_def_ids.any(|d| d == trait_def_id) { + span_err!(self.tcx.sess, item.span, E0371, + "the object type `{}` automatically \ + implements the trait `{}`", + trait_ref.self_ty().user_string(self.tcx), + ty::item_path_str(self.tcx, trait_def_id)); + } + } + } + _ => { } + } + } + _ => { + } } + visit::walk_item(self, item); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8f1b8bf109..5ed93703d9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ There are some shortcomings in this design: use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region}; use middle::def; -use constrained_type_params::identify_constrained_type_params; +use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::region; use middle::resolve_lifetime; @@ -547,14 +547,15 @@ fn is_param<'tcx>(tcx: &ty::ctxt<'tcx>, if let ast::TyPath(None, _) = ast_ty.node { let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap(); match path_res.base_def { - def::DefSelfTy(node_id) => - path_res.depth == 0 && node_id == param_id, - - def::DefTyParam(_, _, def_id, _) => - path_res.depth == 0 && def_id == local_def(param_id), - - _ => - false, + def::DefSelfTy(Some(def_id), None) => { + path_res.depth == 0 && def_id.node == param_id + } + def::DefTyParam(_, _, def_id, _) => { + path_res.depth == 0 && def_id == local_def(param_id) + } + _ => { + false + } } } else { false @@ -575,7 +576,7 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Nullary enum constructors get turned into constants; n-ary enum // constructors get turned into functions. let result_ty = match variant.node.kind { - ast::TupleVariantKind(ref args) if args.len() > 0 => { + ast::TupleVariantKind(ref args) if !args.is_empty() => { let rs = ExplicitRscope; let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect(); ty::mk_ctor_fn(tcx, variant_def_id, &input_tys, enum_scheme.ty) @@ -901,9 +902,10 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref); } - enforce_impl_ty_params_are_constrained(tcx, - generics, - local_def(it.id)); + enforce_impl_params_are_constrained(tcx, + generics, + local_def(it.id), + impl_items); }, ast::ItemTrait(_, _, _, ref trait_items) => { let trait_def = trait_def_of_item(ccx, it); @@ -1034,7 +1036,7 @@ fn convert_struct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, match struct_def.ctor_id { None => {} Some(ctor_id) => { - if struct_def.fields.len() == 0 { + if struct_def.fields.is_empty() { // Enum-like. write_ty_to_tcx(tcx, ctor_id, selfty); @@ -1216,10 +1218,12 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, generics.lifetimes .iter() .enumerate() - .map(|(i, def)| ty::ReEarlyBound(def.lifetime.id, - TypeSpace, - i as u32, - def.lifetime.name)) + .map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: def.lifetime.id, + space: TypeSpace, + index: i as u32, + name: def.lifetime.name + })) .collect(); // Start with the generics in the type parameters... @@ -1690,7 +1694,13 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics); for (index, param) in early_lifetimes.iter().enumerate() { let index = index as u32; - let region = ty::ReEarlyBound(param.lifetime.id, space, index, param.lifetime.name); + let region = + ty::ReEarlyBound(ty::EarlyBoundRegion { + param_id: param.lifetime.id, + space: space, + index: index, + name: param.lifetime.name + }); for bound in ¶m.bounds { let bound_region = ast_region_to_region(ccx.tcx, bound); let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); @@ -1814,7 +1824,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, ty::ty_param(p) => if p.idx > cur_idx { span_err!(tcx.sess, path.span, E0128, "type parameters with a default cannot use \ - forward declared identifiers"); + forward declared identifiers"); }, _ => {} } @@ -1892,7 +1902,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, .flat_map(|predicate| { match *predicate { ast::WherePredicate::BoundPredicate(ref data) => { - if data.bound_lifetimes.len() == 0 && + if data.bound_lifetimes.is_empty() && is_param(ccx.tcx, &data.bounded_ty, param_id) { from_bounds(ccx, &data.bounds).into_iter() @@ -2167,10 +2177,10 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( ty_fold::fold_regions(tcx, value, |region, _| { match region { - ty::ReEarlyBound(id, _, _, name) => { - let def_id = local_def(id); + ty::ReEarlyBound(data) => { + let def_id = local_def(data.param_id); ty::ReFree(ty::FreeRegion { scope: scope, - bound_region: ty::BrNamed(def_id, name) }) + bound_region: ty::BrNamed(def_id, data.name) }) } _ => region } @@ -2179,9 +2189,10 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( } /// Checks that all the type parameters on an impl -fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, - ast_generics: &ast::Generics, - impl_def_id: ast::DefId) +fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, + ast_generics: &ast::Generics, + impl_def_id: ast::DefId, + impl_items: &[P]) { let impl_scheme = ty::lookup_item_type(tcx, impl_def_id); let impl_predicates = ty::lookup_predicates(tcx, impl_def_id); @@ -2191,27 +2202,81 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, // reachable from there, to start (if this is an inherent impl, // then just examine the self type). let mut input_parameters: HashSet<_> = - impl_trait_ref.iter() - .flat_map(|t| t.input_types().iter()) // Types in trait ref, if any - .chain(Some(impl_scheme.ty).iter()) // Self type, always - .flat_map(|t| t.walk()) - .filter_map(|t| t.as_opt_param_ty()) - .collect(); - - identify_constrained_type_params(tcx, - impl_predicates.predicates.as_slice(), - impl_trait_ref, - &mut input_parameters); + ctp::parameters_for_type(impl_scheme.ty).into_iter().collect(); + if let Some(ref trait_ref) = impl_trait_ref { + input_parameters.extend(ctp::parameters_for_trait_ref(trait_ref)); + } + + ctp::identify_constrained_type_params(tcx, + impl_predicates.predicates.as_slice(), + impl_trait_ref, + &mut input_parameters); for (index, ty_param) in ast_generics.ty_params.iter().enumerate() { let param_ty = ty::ParamTy { space: TypeSpace, idx: index as u32, name: ty_param.ident.name }; - if !input_parameters.contains(¶m_ty) { - span_err!(tcx.sess, ty_param.span, E0207, - "the type parameter `{}` is not constrained by the \ - impl trait, self type, or predicates", - param_ty.user_string(tcx)); + if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { + report_unused_parameter(tcx, ty_param.span, "type", ¶m_ty.user_string(tcx)); } } + + // Every lifetime used in an associated type must be constrained. + + let lifetimes_in_associated_types: HashSet<_> = + impl_items.iter() + .filter_map(|item| match item.node { + ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)), + ast::MethodImplItem(..) | ast::MacImplItem(..) => None, + }) + .flat_map(|ty| ctp::parameters_for_type(ty).into_iter()) + .filter_map(|p| match p { + ctp::Parameter::Type(_) => None, + ctp::Parameter::Region(r) => Some(r), + }) + .collect(); + + for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { + let region = ty::EarlyBoundRegion { param_id: lifetime_def.lifetime.id, + space: TypeSpace, + index: index as u32, + name: lifetime_def.lifetime.name }; + if + lifetimes_in_associated_types.contains(®ion) && // (*) + !input_parameters.contains(&ctp::Parameter::Region(region)) + { + report_unused_parameter(tcx, lifetime_def.lifetime.span, + "lifetime", ®ion.name.user_string(tcx)); + } + } + + // (*) This is a horrible concession to reality. I think it'd be + // better to just ban unconstrianed lifetimes outright, but in + // practice people do non-hygenic macros like: + // + // ``` + // macro_rules! __impl_slice_eq1 { + // ($Lhs: ty, $Rhs: ty, $Bound: ident) => { + // impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + // .... + // } + // } + // } + // ``` + // + // In a concession to backwards compatbility, we continue to + // permit those, so long as the lifetimes aren't used in + // associated types. I believe this is sound, because lifetimes + // used elsewhere are not projected back out. +} + +fn report_unused_parameter(tcx: &ty::ctxt, + span: Span, + kind: &str, + name: &str) +{ + span_err!(tcx.sess, span, E0207, + "the {} parameter `{}` is not constrained by the \ + impl trait, self type, or predicates", + kind, name); } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 83d7e98500..fad8fbef2a 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -8,49 +8,101 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::ty::{self}; +use middle::subst; +use middle::ty::{self, Ty}; use std::collections::HashSet; use std::rc::Rc; +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum Parameter { + Type(ty::ParamTy), + Region(ty::EarlyBoundRegion), +} + +pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec { + ty.walk() + .flat_map(|ty| parameters_for_type_shallow(ty).into_iter()) + .collect() +} + +pub fn parameters_for_trait_ref<'tcx>(trait_ref: &Rc>) -> Vec { + let mut region_parameters = + parameters_for_regions_in_substs(&trait_ref.substs); + + let type_parameters = + trait_ref.substs.types.iter() + .flat_map(|ty| parameters_for_type(ty).into_iter()); + + region_parameters.extend(type_parameters); + + region_parameters +} + +fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec { + match ty.sty { + ty::ty_param(ref d) => + vec![Parameter::Type(d.clone())], + ty::ty_rptr(region, _) => + parameters_for_region(region).into_iter().collect(), + ty::ty_struct(_, substs) | + ty::ty_enum(_, substs) => + parameters_for_regions_in_substs(substs), + ty::ty_trait(ref data) => + parameters_for_regions_in_substs(&data.principal.skip_binder().substs), + _ => + vec![], + } +} + +fn parameters_for_regions_in_substs(substs: &subst::Substs) -> Vec { + substs.regions() + .iter() + .filter_map(|r| parameters_for_region(r)) + .collect() +} + +fn parameters_for_region(region: &ty::Region) -> Option { + match *region { + ty::ReEarlyBound(data) => Some(Parameter::Region(data)), + _ => None, + } +} + pub fn identify_constrained_type_params<'tcx>(_tcx: &ty::ctxt<'tcx>, predicates: &[ty::Predicate<'tcx>], impl_trait_ref: Option>>, - input_parameters: &mut HashSet) + input_parameters: &mut HashSet) { loop { let num_inputs = input_parameters.len(); - let projection_predicates = + let poly_projection_predicates = // : iterator over PolyProjectionPredicate predicates.iter() .filter_map(|predicate| { match *predicate { - // Ignore higher-ranked binders. For the purposes - // of this check, they don't matter because they - // only affect named regions, and we're just - // concerned about type parameters here. - ty::Predicate::Projection(ref data) => Some(data.0.clone()), + ty::Predicate::Projection(ref data) => Some(data.clone()), _ => None, } }); - for projection in projection_predicates { + for poly_projection in poly_projection_predicates { + // Note that we can skip binder here because the impl + // trait ref never contains any late-bound regions. + let projection = poly_projection.skip_binder(); + // Special case: watch out for some kind of sneaky attempt - // to project out an associated type defined by this very trait. - if Some(projection.projection_ty.trait_ref.clone()) == impl_trait_ref { + // to project out an associated type defined by this very + // trait. + let unbound_trait_ref = &projection.projection_ty.trait_ref; + if Some(unbound_trait_ref.clone()) == impl_trait_ref { continue; } - let relies_only_on_inputs = - projection.projection_ty.trait_ref.input_types() - .iter() - .flat_map(|t| t.walk()) - .filter_map(|t| t.as_opt_param_ty()) - .all(|t| input_parameters.contains(&t)); - + let inputs = parameters_for_trait_ref(&projection.projection_ty.trait_ref); + let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); if relies_only_on_inputs { - input_parameters.extend( - projection.ty.walk().filter_map(|t| t.as_opt_param_ty())); + input_parameters.extend(parameters_for_type(projection.ty)); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a8d93c8bd1..b17702cfb8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -179,7 +179,9 @@ register_diagnostics! { E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0368, // binary operation `=` cannot be applied to types - E0369 // binary operation `` cannot be applied to types + E0369, // binary operation `` cannot be applied to types + E0371, // impl Trait for Trait is illegal + E0372 // impl Trait for Trait where Trait is not object safe } __build_diagnostic_array! { DIAGNOSTICS } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9d6c04b1ad..be3fc860b2 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -200,7 +200,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, msg(), ty::type_err_to_str(tcx, terr)); - ty::note_and_explain_type_err(tcx, terr); + ty::note_and_explain_type_err(tcx, terr, span); false } } diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index b83d8fc6af..7575f12878 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -18,34 +18,121 @@ //! defined on type `X`, we only consider the definition of the type `X` //! and the definitions of any types it references. //! -//! We only infer variance for type parameters found on *types*: structs, -//! enums, and traits. We do not infer variance for type parameters found -//! on fns or impls. This is because those things are not type definitions -//! and variance doesn't really make sense in that context. -//! -//! It is worth covering what variance means in each case. For structs and -//! enums, I think it is fairly straightforward. The variance of the type +//! We only infer variance for type parameters found on *data types* +//! like structs and enums. In these cases, there is fairly straightforward +//! explanation for what variance means. The variance of the type //! or lifetime parameters defines whether `T` is a subtype of `T` //! (resp. `T<'a>` and `T<'b>`) based on the relationship of `A` and `B` -//! (resp. `'a` and `'b`). (FIXME #3598 -- we do not currently make use of -//! the variances we compute for type parameters.) +//! (resp. `'a` and `'b`). +//! +//! We do not infer variance for type parameters found on traits, fns, +//! or impls. Variance on trait parameters can make indeed make sense +//! (and we used to compute it) but it is actually rather subtle in +//! meaning and not that useful in practice, so we removed it. See the +//! addendum for some details. Variances on fn/impl parameters, otoh, +//! doesn't make sense because these parameters are instantiated and +//! then forgotten, they don't persist in types or compiled +//! byproducts. +//! +//! ### The algorithm +//! +//! The basic idea is quite straightforward. We iterate over the types +//! defined and, for each use of a type parameter X, accumulate a +//! constraint indicating that the variance of X must be valid for the +//! variance of that use site. We then iteratively refine the variance of +//! X until all constraints are met. There is *always* a sol'n, because at +//! the limit we can declare all type parameters to be invariant and all +//! constraints will be satisfied. +//! +//! As a simple example, consider: +//! +//! enum Option { Some(A), None } +//! enum OptionalFn { Some(|B|), None } +//! enum OptionalMap { Some(|C| -> C), None } +//! +//! Here, we will generate the constraints: +//! +//! 1. V(A) <= + +//! 2. V(B) <= - +//! 3. V(C) <= + +//! 4. V(C) <= - +//! +//! These indicate that (1) the variance of A must be at most covariant; +//! (2) the variance of B must be at most contravariant; and (3, 4) the +//! variance of C must be at most covariant *and* contravariant. All of these +//! results are based on a variance lattice defined as follows: +//! +//! * Top (bivariant) +//! - + +//! o Bottom (invariant) +//! +//! Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the +//! optimal solution. Note that there is always a naive solution which +//! just declares all variables to be invariant. +//! +//! You may be wondering why fixed-point iteration is required. The reason +//! is that the variance of a use site may itself be a function of the +//! variance of other type parameters. In full generality, our constraints +//! take the form: +//! +//! V(X) <= Term +//! Term := + | - | * | o | V(X) | Term x Term +//! +//! Here the notation V(X) indicates the variance of a type/region +//! parameter `X` with respect to its defining class. `Term x Term` +//! represents the "variance transform" as defined in the paper: +//! +//! If the variance of a type variable `X` in type expression `E` is `V2` +//! and the definition-site variance of the [corresponding] type parameter +//! of a class `C` is `V1`, then the variance of `X` in the type expression +//! `C` is `V3 = V1.xform(V2)`. +//! +//! ### Constraints +//! +//! If I have a struct or enum with where clauses: +//! +//! struct Foo { ... } +//! +//! you might wonder whether the variance of `T` with respect to `Bar` +//! affects the variance `T` with respect to `Foo`. I claim no. The +//! reason: assume that `T` is invariant w/r/t `Bar` but covariant w/r/t +//! `Foo`. And then we have a `Foo` that is upcast to `Foo`, where +//! `X <: Y`. However, while `X : Bar`, `Y : Bar` does not hold. In that +//! case, the upcast will be illegal, but not because of a variance +//! failure, but rather because the target type `Foo` is itself just +//! not well-formed. Basically we get to assume well-formedness of all +//! types involved before considering variance. +//! +//! ### Addendum: Variance on traits //! -//! ### Variance on traits +//! As mentioned above, we used to permit variance on traits. This was +//! computed based on the appearance of trait type parameters in +//! method signatures and was used to represent the compatibility of +//! vtables in trait objects (and also "virtual" vtables or dictionary +//! in trait bounds). One complication was that variance for +//! associated types is less obvious, since they can be projected out +//! and put to myriad uses, so it's not clear when it is safe to allow +//! `X::Bar` to vary (or indeed just what that means). Moreover (as +//! covered below) all inputs on any trait with an associated type had +//! to be invariant, limiting the applicability. Finally, the +//! annotations (`MarkerTrait`, `PhantomFn`) needed to ensure that all +//! trait type parameters had a variance were confusing and annoying +//! for little benefit. //! -//! The meaning of variance for trait parameters is more subtle and worth -//! expanding upon. There are in fact two uses of the variance values we -//! compute. +//! Just for historical reference,I am going to preserve some text indicating +//! how one could interpret variance and trait matching. //! -//! #### Trait variance and object types +//! #### Variance and object types //! -//! The first is for object types. Just as with structs and enums, we can -//! decide the subtyping relationship between two object types `&Trait` -//! and `&Trait` based on the relationship of `A` and `B`. Note that -//! for object types we ignore the `Self` type parameter -- it is unknown, -//! and the nature of dynamic dispatch ensures that we will always call a +//! Just as with structs and enums, we can decide the subtyping +//! relationship between two object types `&Trait` and `&Trait` +//! based on the relationship of `A` and `B`. Note that for object +//! types we ignore the `Self` type parameter -- it is unknown, and +//! the nature of dynamic dispatch ensures that we will always call a //! function that is expected the appropriate `Self` type. However, we -//! must be careful with the other type parameters, or else we could end -//! up calling a function that is expecting one type but provided another. +//! must be careful with the other type parameters, or else we could +//! end up calling a function that is expecting one type but provided +//! another. //! //! To see what I mean, consider a trait like so: //! @@ -135,104 +222,24 @@ //! //! These conditions are satisfied and so we are happy. //! -//! ### The algorithm +//! #### Variance and associated types //! -//! The basic idea is quite straightforward. We iterate over the types -//! defined and, for each use of a type parameter X, accumulate a -//! constraint indicating that the variance of X must be valid for the -//! variance of that use site. We then iteratively refine the variance of -//! X until all constraints are met. There is *always* a sol'n, because at -//! the limit we can declare all type parameters to be invariant and all -//! constraints will be satisfied. -//! -//! As a simple example, consider: -//! -//! enum Option { Some(A), None } -//! enum OptionalFn { Some(|B|), None } -//! enum OptionalMap { Some(|C| -> C), None } -//! -//! Here, we will generate the constraints: -//! -//! 1. V(A) <= + -//! 2. V(B) <= - -//! 3. V(C) <= + -//! 4. V(C) <= - -//! -//! These indicate that (1) the variance of A must be at most covariant; -//! (2) the variance of B must be at most contravariant; and (3, 4) the -//! variance of C must be at most covariant *and* contravariant. All of these -//! results are based on a variance lattice defined as follows: -//! -//! * Top (bivariant) -//! - + -//! o Bottom (invariant) -//! -//! Based on this lattice, the solution V(A)=+, V(B)=-, V(C)=o is the -//! optimal solution. Note that there is always a naive solution which -//! just declares all variables to be invariant. -//! -//! You may be wondering why fixed-point iteration is required. The reason -//! is that the variance of a use site may itself be a function of the -//! variance of other type parameters. In full generality, our constraints -//! take the form: -//! -//! V(X) <= Term -//! Term := + | - | * | o | V(X) | Term x Term -//! -//! Here the notation V(X) indicates the variance of a type/region -//! parameter `X` with respect to its defining class. `Term x Term` -//! represents the "variance transform" as defined in the paper: -//! -//! If the variance of a type variable `X` in type expression `E` is `V2` -//! and the definition-site variance of the [corresponding] type parameter -//! of a class `C` is `V1`, then the variance of `X` in the type expression -//! `C` is `V3 = V1.xform(V2)`. -//! -//! ### Constraints -//! -//! If I have a struct or enum with where clauses: -//! -//! struct Foo { ... } -//! -//! you might wonder whether the variance of `T` with respect to `Bar` -//! affects the variance `T` with respect to `Foo`. I claim no. The -//! reason: assume that `T` is invariant w/r/t `Bar` but covariant w/r/t -//! `Foo`. And then we have a `Foo` that is upcast to `Foo`, where -//! `X <: Y`. However, while `X : Bar`, `Y : Bar` does not hold. In that -//! case, the upcast will be illegal, but not because of a variance -//! failure, but rather because the target type `Foo` is itself just -//! not well-formed. Basically we get to assume well-formedness of all -//! types involved before considering variance. -//! -//! ### Associated types -//! -//! Any trait with an associated type is invariant with respect to all -//! of its inputs. To see why this makes sense, consider what -//! subtyping for a trait reference means: +//! Traits with associated types -- or at minimum projection +//! expressions -- must be invariant with respect to all of their +//! inputs. To see why this makes sense, consider what subtyping for a +//! trait reference means: //! //! <: //! -//! means that if I know that `T as Trait`, -//! I also know that `U as -//! Trait`. Moreover, if you think of it as -//! dictionary passing style, it means that -//! a dictionary for `` is safe -//! to use where a dictionary for `` is expected. -//! -//! The problem is that when you can -//! project types out from ``, -//! the relationship to types projected out -//! of `` is completely unknown -//! unless `T==U` (see #21726 for more -//! details). Making `Trait` invariant -//! ensures that this is true. +//! means that if I know that `T as Trait`, I also know that `U as +//! Trait`. Moreover, if you think of it as dictionary passing style, +//! it means that a dictionary for `` is safe to use where +//! a dictionary for `` is expected. //! -//! *Historical note: we used to preserve this invariant another way, -//! by tweaking the subtyping rules and requiring that when a type `T` -//! appeared as part of a projection, that was considered an invariant -//! location, but this version does away with the need for those -//! somewhat "special-case-feeling" rules.* +//! The problem is that when you can project types out from ``, the relationship to types projected out of `` +//! is completely unknown unless `T==U` (see #21726 for more +//! details). Making `Trait` invariant ensures that this is true. //! //! Another related reason is that if we didn't make traits with //! associated types invariant, then projection is no longer a @@ -383,7 +390,6 @@ fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, fn lang_items(tcx: &ty::ctxt) -> Vec<(ast::NodeId,Vec)> { let all = vec![ - (tcx.lang_items.phantom_fn(), vec![ty::Contravariant, ty::Covariant]), (tcx.lang_items.phantom_data(), vec![ty::Covariant]), (tcx.lang_items.unsafe_cell_type(), vec![ty::Invariant]), @@ -520,6 +526,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { self.add_inferreds_for_item(item.id, false, generics); } ast::ItemTrait(_, ref generics, _, _) => { + // Note: all inputs for traits are ultimately + // constrained to be invariant. See `visit_item` in + // the impl for `ConstraintContext` below. self.add_inferreds_for_item(item.id, true, generics); visit::walk_item(self, item); } @@ -644,39 +653,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { ast::ItemTrait(..) => { let trait_def = ty::lookup_trait_def(tcx, did); - let predicates = ty::lookup_super_predicates(tcx, did); - self.add_constraints_from_predicates(&trait_def.generics, - predicates.predicates.as_slice(), - self.covariant); - - let trait_items = ty::trait_items(tcx, did); - for trait_item in &*trait_items { - match *trait_item { - ty::MethodTraitItem(ref method) => { - self.add_constraints_from_predicates( - &method.generics, - method.predicates.predicates.get_slice(FnSpace), - self.contravariant); - - self.add_constraints_from_sig( - &method.generics, - &method.fty.sig, - self.covariant); - } - ty::TypeTraitItem(ref data) => { - // Any trait with an associated type is - // invariant with respect to all of its - // inputs. See length discussion in the comment - // on this module. - let projection_ty = ty::mk_projection(tcx, - trait_def.trait_ref.clone(), - data.name); - self.add_constraints_from_ty(&trait_def.generics, - projection_ty, - self.invariant); - } - } - } + self.add_constraints_from_trait_ref(&trait_def.generics, + &trait_def.trait_ref, + self.invariant); } ast::ItemExternCrate(_) | @@ -1045,69 +1024,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - fn add_constraints_from_predicates(&mut self, - generics: &ty::Generics<'tcx>, - predicates: &[ty::Predicate<'tcx>], - variance: VarianceTermPtr<'a>) { - debug!("add_constraints_from_generics({})", - generics.repr(self.tcx())); - - for predicate in predicates.iter() { - match *predicate { - ty::Predicate::Trait(ty::Binder(ref data)) => { - self.add_constraints_from_trait_ref(generics, &*data.trait_ref, variance); - } - - ty::Predicate::Equate(ty::Binder(ref data)) => { - // A == B is only true if A and B are the same - // types, not subtypes of one another, so this is - // an invariant position: - self.add_constraints_from_ty(generics, data.0, self.invariant); - self.add_constraints_from_ty(generics, data.1, self.invariant); - } - - ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { - // Why contravariant on both? Let's consider: - // - // Under what conditions is `(T:'t) <: (U:'u)`, - // meaning that `(T:'t) => (U:'u)`. The answer is - // if `U <: T` or `'u <= 't`. Let's see some examples: - // - // (T: 'big) => (T: 'small) - // where 'small <= 'big - // - // (&'small Foo: 't) => (&'big Foo: 't) - // where 'small <= 'big - // note that &'big Foo <: &'small Foo - - let variance_r = self.xform(variance, self.contravariant); - self.add_constraints_from_ty(generics, data.0, variance_r); - self.add_constraints_from_region(generics, data.1, variance_r); - } - - ty::Predicate::RegionOutlives(ty::Binder(ref data)) => { - // `'a : 'b` is still true if 'a gets bigger - self.add_constraints_from_region(generics, data.0, variance); - - // `'a : 'b` is still true if 'b gets smaller - let variance_r = self.xform(variance, self.contravariant); - self.add_constraints_from_region(generics, data.1, variance_r); - } - - ty::Predicate::Projection(ty::Binder(ref data)) => { - self.add_constraints_from_trait_ref(generics, - &*data.projection_ty.trait_ref, - variance); - - // as the equality predicate above, a binder is a - // type equality relation, not a subtyping - // relation - self.add_constraints_from_ty(generics, data.ty, self.invariant); - } - } - } - } - /// Adds constraints appropriate for a function with signature /// `sig` appearing in a context with ambient variance `variance` fn add_constraints_from_sig(&mut self, @@ -1130,9 +1046,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { region: ty::Region, variance: VarianceTermPtr<'a>) { match region { - ty::ReEarlyBound(param_id, _, _, _) => { - if self.is_to_be_inferred(param_id) { - let index = self.inferred_index(param_id); + ty::ReEarlyBound(ref data) => { + if self.is_to_be_inferred(data.param_id) { + let index = self.inferred_index(data.param_id); self.add_constraint(index, variance); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index aa17bf20d7..f14437b71b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -10,6 +10,8 @@ //! Support for inlining external documentation into the current AST. +use std::collections::HashSet; + use syntax::ast; use syntax::ast_util; use syntax::attr::AttrMetaMethods; @@ -150,18 +152,21 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt, let def = ty::lookup_trait_def(tcx, did); let trait_items = ty::trait_items(tcx, did).clean(cx); let predicates = ty::lookup_predicates(tcx, did); + let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + let generics = filter_non_trait_generics(did, generics); + let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); clean::Trait { unsafety: def.unsafety, - generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx), + generics: generics, items: trait_items, - bounds: vec![], // supertraits can be found in the list of predicates + bounds: supertrait_bounds, } } fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function { let t = ty::lookup_item_type(tcx, did); - let (decl, style) = match t.ty.sty { - ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety), + let (decl, style, abi) = match t.ty.sty { + ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; let predicates = ty::lookup_predicates(tcx, did); @@ -169,6 +174,7 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> decl: decl, generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), unsafety: style, + abi: abi, } } @@ -331,9 +337,10 @@ fn build_impl(cx: &DocContext, let did = assoc_ty.def_id; let type_scheme = ty::lookup_item_type(tcx, did); let predicates = ty::lookup_predicates(tcx, did); - // Not sure the choice of ParamSpace actually matters here, because an - // associated type won't have generics on the LHS - let typedef = (type_scheme, predicates, subst::ParamSpace::TypeSpace).clean(cx); + // Not sure the choice of ParamSpace actually matters here, + // because an associated type won't have generics on the LHS + let typedef = (type_scheme, predicates, + subst::ParamSpace::TypeSpace).clean(cx); Some(clean::Item { name: Some(assoc_ty.name.clean(cx)), inner: clean::TypedefItem(typedef), @@ -395,16 +402,19 @@ fn build_module(cx: &DocContext, tcx: &ty::ctxt, is_crate: false, }; - // FIXME: this doesn't handle reexports inside the module itself. - // Should they be handled? fn fill_in(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId, items: &mut Vec) { + // If we're reexporting a reexport it may actually reexport something in + // two namespaces, so the target may be listed twice. Make sure we only + // visit each node at most once. + let mut visited = HashSet::new(); csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| { match def { decoder::DlDef(def::DefForeignMod(did)) => { fill_in(cx, tcx, did, items); } decoder::DlDef(def) if vis == ast::Public => { + if !visited.insert(def) { return } match try_inline_def(cx, tcx, def) { Some(i) => items.extend(i.into_iter()), None => {} @@ -446,3 +456,48 @@ fn build_static(cx: &DocContext, tcx: &ty::ctxt, expr: "\n\n\n".to_string(), // trigger the "[definition]" links } } + +/// A trait's generics clause actually contains all of the predicates for all of +/// its associated types as well. We specifically move these clauses to the +/// associated types instead when displaying, so when we're genering the +/// generics for the trait itself we need to be sure to remove them. +/// +/// The inverse of this filtering logic can be found in the `Clean` +/// implementation for `AssociatedType` +fn filter_non_trait_generics(trait_did: ast::DefId, mut g: clean::Generics) + -> clean::Generics { + g.where_predicates.retain(|pred| { + match *pred { + clean::WherePredicate::BoundPredicate { + ty: clean::QPath { + self_type: box clean::Generic(ref s), + trait_: box clean::ResolvedPath { did, .. }, + name: ref _name, + }, .. + } => *s != "Self" || did != trait_did, + _ => true, + } + }); + return g; +} + +/// Supertrait bounds for a trait are also listed in the generics coming from +/// the metadata for a crate, so we want to separate those out and create a new +/// list of explicit supertrait bounds to render nicely. +fn separate_supertrait_bounds(mut g: clean::Generics) + -> (clean::Generics, Vec) { + let mut ty_bounds = Vec::new(); + g.where_predicates.retain(|pred| { + match *pred { + clean::WherePredicate::BoundPredicate { + ty: clean::Generic(ref s), + ref bounds + } if *s == "Self" => { + ty_bounds.extend(bounds.iter().cloned()); + false + } + _ => true, + } + }); + (g, ty_bounds) +} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e0ed83f401..243db61007 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -44,9 +44,10 @@ use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace}; use rustc::middle::ty; use rustc::middle::stability; +use std::collections::HashMap; +use std::path::PathBuf; use std::rc::Rc; use std::u32; -use std::path::PathBuf; use core::DocContext; use doctree; @@ -57,6 +58,7 @@ use visit_ast; pub static SCHEMA_VERSION: &'static str = "0.8.3"; mod inline; +mod simplify; // extract the stability index for a node from tcx, if possible fn get_stability(cx: &DocContext, def_id: ast::DefId) -> Option { @@ -119,6 +121,7 @@ pub struct Crate { pub module: Option, pub externs: Vec<(ast::CrateNum, ExternalCrate)>, pub primitives: Vec, + pub external_traits: HashMap, } impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { @@ -197,6 +200,8 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { module: Some(module), externs: externs, primitives: primitives, + external_traits: cx.external_traits.borrow_mut().take() + .unwrap_or(HashMap::new()), } } } @@ -493,6 +498,35 @@ pub enum TyParamBound { TraitBound(PolyTrait, ast::TraitBoundModifier) } +impl TyParamBound { + fn maybe_sized(cx: &DocContext) -> TyParamBound { + use syntax::ast::TraitBoundModifier as TBM; + let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx); + if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound { + *tbm = TBM::Maybe + }; + sized_bound + } + + fn is_sized_bound(&self, cx: &DocContext) -> bool { + use syntax::ast::TraitBoundModifier as TBM; + if let Some(tcx) = cx.tcx_opt() { + let sized_did = match tcx.lang_items.sized_trait() { + Some(did) => did, + None => return false + }; + if let TyParamBound::TraitBound(PolyTrait { + trait_: Type::ResolvedPath { did, .. }, .. + }, TBM::None) = *self { + if did == sized_did { + return true + } + } + } + false + } +} + impl Clean for ast::TyParamBound { fn clean(&self, cx: &DocContext) -> TyParamBound { match *self { @@ -678,7 +712,7 @@ impl<'tcx> Clean>> for subst::Substs<'tcx> { trait_: t.clean(cx), lifetimes: vec![] }, ast::TraitBoundModifier::None))); - if v.len() > 0 {Some(v)} else {None} + if !v.is_empty() {Some(v)} else {None} } } @@ -721,7 +755,7 @@ impl Clean> for ty::Region { ty::ReStatic => Some(Lifetime::statik()), ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(token::get_name(name).to_string())), - ty::ReEarlyBound(_, _, _, name) => Some(Lifetime(name.clean(cx))), + ty::ReEarlyBound(ref data) => Some(Lifetime(data.name.clean(cx))), ty::ReLateBound(..) | ty::ReFree(..) | @@ -830,7 +864,9 @@ impl<'tcx> Clean for ty::ProjectionTy<'tcx> { fn clean(&self, cx: &DocContext) -> Type { let trait_ = match self.trait_ref.clean(cx) { TyParamBound::TraitBound(t, _) => t.trait_, - TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"), + TyParamBound::RegionBound(_) => { + panic!("cleaning a trait got a region") + } }; Type::QPath { name: self.item_name.clean(cx), @@ -863,32 +899,13 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, subst::ParamSpace) { fn clean(&self, cx: &DocContext) -> Generics { use std::collections::HashSet; - use syntax::ast::TraitBoundModifier as TBM; use self::WherePredicate as WP; - fn has_sized_bound(bounds: &[TyParamBound], cx: &DocContext) -> bool { - if let Some(tcx) = cx.tcx_opt() { - let sized_did = match tcx.lang_items.sized_trait() { - Some(did) => did, - None => return false - }; - for bound in bounds { - if let TyParamBound::TraitBound(PolyTrait { - trait_: Type::ResolvedPath { did, .. }, .. - }, TBM::None) = *bound { - if did == sized_did { - return true - } - } - } - } - false - } - let (gens, preds, space) = *self; - // Bounds in the type_params and lifetimes fields are repeated in the predicates - // field (see rustc_typeck::collect::ty_generics), so remove them. + // Bounds in the type_params and lifetimes fields are repeated in the + // predicates field (see rustc_typeck::collect::ty_generics), so remove + // them. let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| { tp.clean(cx) }).collect::>(); @@ -898,33 +915,38 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, srp.clean(cx) }).collect::>(); - let where_predicates = preds.predicates.get_slice(space).to_vec().clean(cx); + let mut where_predicates = preds.predicates.get_slice(space) + .to_vec().clean(cx); - // Type parameters have a Sized bound by default unless removed with ?Sized. - // Scan through the predicates and mark any type parameter with a Sized - // bound, removing the bounds as we find them. + // Type parameters and have a Sized bound by default unless removed with + // ?Sized. Scan through the predicates and mark any type parameter with + // a Sized bound, removing the bounds as we find them. + // + // Note that associated types also have a sized bound by default, but we + // don't actually konw the set of associated types right here so that's + // handled in cleaning associated types let mut sized_params = HashSet::new(); - let mut where_predicates = where_predicates.into_iter().filter_map(|pred| { - if let WP::BoundPredicate { ty: Type::Generic(ref g), ref bounds } = pred { - if has_sized_bound(&**bounds, cx) { - sized_params.insert(g.clone()); - return None + where_predicates.retain(|pred| { + match *pred { + WP::BoundPredicate { ty: Generic(ref g), ref bounds } => { + if bounds.iter().any(|b| b.is_sized_bound(cx)) { + sized_params.insert(g.clone()); + false + } else { + true + } } + _ => true, } - Some(pred) - }).collect::>(); + }); - // Finally, run through the type parameters again and insert a ?Sized unbound for - // any we didn't find to be Sized. + // Run through the type parameters again and insert a ?Sized + // unbound for any we didn't find to be Sized. for tp in &stripped_typarams { if !sized_params.contains(&tp.name) { - let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx); - if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound { - *tbm = TBM::Maybe - }; where_predicates.push(WP::BoundPredicate { ty: Type::Generic(tp.name.clone()), - bounds: vec![sized_bound] + bounds: vec![TyParamBound::maybe_sized(cx)], }) } } @@ -934,9 +956,9 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics<'tcx>, // and instead see `where T: Foo + Bar + Sized + 'a` Generics { - type_params: stripped_typarams, + type_params: simplify::ty_params(stripped_typarams), lifetimes: stripped_lifetimes, - where_predicates: where_predicates + where_predicates: simplify::where_clauses(cx, where_predicates), } } } @@ -1032,6 +1054,7 @@ pub struct Function { pub decl: FnDecl, pub generics: Generics, pub unsafety: ast::Unsafety, + pub abi: abi::Abi } impl Clean for doctree::Function { @@ -1047,6 +1070,7 @@ impl Clean for doctree::Function { decl: self.decl.clean(cx), generics: self.generics.clean(cx), unsafety: self.unsafety, + abi: self.abi, }), } } @@ -1274,6 +1298,35 @@ impl<'tcx> Clean for ty::Method<'tcx> { } }; + let generics = (&self.generics, &self.predicates, + subst::FnSpace).clean(cx); + let decl = (self.def_id, &sig).clean(cx); + let provided = match self.container { + ty::ImplContainer(..) => false, + ty::TraitContainer(did) => { + ty::provided_trait_methods(cx.tcx(), did).iter().any(|m| { + m.def_id == self.def_id + }) + } + }; + let inner = if provided { + MethodItem(Method { + unsafety: self.fty.unsafety, + generics: generics, + self_: self_, + decl: decl, + abi: self.fty.abi + }) + } else { + TyMethodItem(TyMethod { + unsafety: self.fty.unsafety, + generics: generics, + self_: self_, + decl: decl, + abi: self.fty.abi + }) + }; + Item { name: Some(self.name.clean(cx)), visibility: Some(ast::Inherited), @@ -1281,13 +1334,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { def_id: self.def_id, attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), source: Span::empty(), - inner: TyMethodItem(TyMethod { - unsafety: self.fty.unsafety, - generics: (&self.generics, &self.predicates, subst::FnSpace).clean(cx), - self_: self_, - decl: (self.def_id, &sig).clean(cx), - abi: self.fty.abi - }) + inner: inner, } } } @@ -1365,6 +1412,7 @@ pub enum PrimitiveType { Slice, Array, PrimitiveTuple, + PrimitiveRawPointer, } #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] @@ -1380,6 +1428,21 @@ pub enum TypeKind { TypeTypedef, } +impl Type { + pub fn primitive_type(&self) -> Option { + match *self { + Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p), + Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice), + FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => { + Some(Array) + } + Tuple(..) => Some(PrimitiveTuple), + RawPointer(..) => Some(PrimitiveRawPointer), + _ => None, + } + } +} + impl PrimitiveType { fn from_str(s: &str) -> Option { match s { @@ -1401,6 +1464,7 @@ impl PrimitiveType { "array" => Some(Array), "slice" => Some(Slice), "tuple" => Some(PrimitiveTuple), + "pointer" => Some(PrimitiveRawPointer), _ => None, } } @@ -1446,6 +1510,7 @@ impl PrimitiveType { Array => "array", Slice => "slice", PrimitiveTuple => "tuple", + PrimitiveRawPointer => "pointer", } } @@ -1587,17 +1652,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { } ty::ty_tup(ref t) => Tuple(t.clean(cx)), - ty::ty_projection(ref data) => { - let trait_ref = match data.trait_ref.clean(cx) { - TyParamBound::TraitBound(t, _) => t.trait_, - TyParamBound::RegionBound(_) => panic!("cleaning a trait got a region??"), - }; - Type::QPath { - name: data.item_name.clean(cx), - self_type: box data.trait_ref.self_ty().clean(cx), - trait_: box trait_ref, - } - } + ty::ty_projection(ref data) => data.clean(cx), ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()), @@ -1765,7 +1820,7 @@ impl<'tcx> Clean for ty::VariantInfo<'tcx> { fn clean(&self, cx: &DocContext) -> Item { // use syntax::parse::token::special_idents::unnamed_field; let kind = match self.arg_names.as_ref().map(|s| &**s) { - None | Some([]) if self.args.len() == 0 => CLikeVariant, + None | Some([]) if self.args.is_empty() => CLikeVariant, None | Some([]) => { TupleVariant(self.args.clean(cx)) } @@ -1819,7 +1874,7 @@ impl Clean for ast::VariantKind { fn clean(&self, cx: &DocContext) -> VariantKind { match self { &ast::TupleVariantKind(ref args) => { - if args.len() == 0 { + if args.is_empty() { CLikeVariant } else { TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect()) @@ -1871,6 +1926,22 @@ pub struct Path { pub segments: Vec, } +impl Path { + pub fn singleton(name: String) -> Path { + Path { + global: false, + segments: vec![PathSegment { + name: name, + params: PathParameters::AngleBracketed { + lifetimes: Vec::new(), + types: Vec::new(), + bindings: Vec::new() + } + }] + } + } +} + impl Clean for ast::Path { fn clean(&self, cx: &DocContext) -> Path { Path { @@ -2262,7 +2333,14 @@ impl Clean for ast::PathListItem { impl Clean> for ast::ForeignMod { fn clean(&self, cx: &DocContext) -> Vec { - self.items.clean(cx) + let mut items = self.items.clean(cx); + for item in &mut items { + match item.inner { + ForeignFunctionItem(ref mut f) => f.abi = self.abi, + _ => {} + } + } + items } } @@ -2274,6 +2352,7 @@ impl Clean for ast::ForeignItem { decl: decl.clean(cx), generics: generics.clean(cx), unsafety: ast::Unsafety::Unsafe, + abi: abi::Rust, }) } ast::ForeignItemStatic(ref ty, mutbl) => { @@ -2506,21 +2585,66 @@ impl Clean for attr::Stability { impl Clean for ty::AssociatedType { fn clean(&self, cx: &DocContext) -> Item { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let predicates = ty::lookup_predicates(cx.tcx(), self.container.id()); + let generics = match self.container { + ty::TraitContainer(did) => { + let def = ty::lookup_trait_def(cx.tcx(), did); + (&def.generics, &predicates, subst::TypeSpace).clean(cx) + } + ty::ImplContainer(did) => { + let ty = ty::lookup_item_type(cx.tcx(), did); + (&ty.generics, &predicates, subst::TypeSpace).clean(cx) + } + }; + let my_name = self.name.clean(cx); + let mut bounds = generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>(); + + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { bounds.remove(i); } + None => bounds.push(TyParamBound::maybe_sized(cx)), + } + Item { source: DUMMY_SP.clean(cx), name: Some(self.name.clean(cx)), - attrs: Vec::new(), - // FIXME(#20727): bounds are missing and need to be filled in from the - // predicates on the trait itself - inner: AssociatedTypeItem(vec![], None), - visibility: None, + attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), + inner: AssociatedTypeItem(bounds, None), + visibility: self.vis.clean(cx), def_id: self.def_id, - stability: None, + stability: stability::lookup(cx.tcx(), self.def_id).clean(cx), } } } -impl<'a> Clean for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, ParamSpace) { +impl<'a> Clean for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, + ParamSpace) { fn clean(&self, cx: &DocContext) -> Typedef { let (ref ty_scheme, ref predicates, ps) = *self; Typedef { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs new file mode 100644 index 0000000000..03f056a692 --- /dev/null +++ b/src/librustdoc/clean/simplify.rs @@ -0,0 +1,180 @@ +// 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. + +//! Simplification of where clauses and parameter bounds into a prettier and +//! more canonical form. +//! +//! Currently all cross-crate-inlined function use `middle::ty` to reconstruct +//! the AST (e.g. see all of `clean::inline`), but this is not always a +//! non-lossy transformation. The current format of storage for where clauses +//! for functions and such is simply a list of predicates. One example of this +//! is that the AST predicate of: +//! +//! where T: Trait +//! +//! is encoded as: +//! +//! where T: Trait, ::Foo = Bar +//! +//! This module attempts to reconstruct the original where and/or parameter +//! bounds by special casing scenarios such as these. Fun! + +use std::mem; +use std::collections::HashMap; + +use rustc::middle::subst; +use rustc::middle::ty; +use syntax::ast; + +use clean::PathParameters as PP; +use clean::WherePredicate as WP; +use clean::{self, Clean}; +use core::DocContext; + +pub fn where_clauses(cx: &DocContext, clauses: Vec) -> Vec { + // First, partition the where clause into its separate components + let mut params = HashMap::new(); + let mut lifetimes = Vec::new(); + let mut equalities = Vec::new(); + let mut tybounds = Vec::new(); + for clause in clauses { + match clause { + WP::BoundPredicate { ty, bounds } => { + match ty { + clean::Generic(s) => params.entry(s).or_insert(Vec::new()) + .extend(bounds), + t => tybounds.push((t, ty_bounds(bounds))), + } + } + WP::RegionPredicate { lifetime, bounds } => { + lifetimes.push((lifetime, bounds)); + } + WP::EqPredicate { lhs, rhs } => equalities.push((lhs, rhs)), + } + } + + // Simplify the type parameter bounds on all the generics + let mut params = params.into_iter().map(|(k, v)| { + (k, ty_bounds(v)) + }).collect::>(); + + // Look for equality predicates on associated types that can be merged into + // general bound predicates + equalities.retain(|&(ref lhs, ref rhs)| { + let (self_, trait_, name) = match *lhs { + clean::QPath { ref self_type, ref trait_, ref name } => { + (self_type, trait_, name) + } + _ => return true, + }; + let generic = match **self_ { + clean::Generic(ref s) => s, + _ => return true, + }; + let trait_did = match **trait_ { + clean::ResolvedPath { did, .. } => did, + _ => return true, + }; + let bounds = match params.get_mut(generic) { + Some(bound) => bound, + None => return true, + }; + !bounds.iter_mut().any(|b| { + let trait_ref = match *b { + clean::TraitBound(ref mut tr, _) => tr, + clean::RegionBound(..) => return false, + }; + let (did, path) = match trait_ref.trait_ { + clean::ResolvedPath { did, ref mut path, ..} => (did, path), + _ => return false, + }; + // If this QPath's trait `trait_did` is the same as, or a supertrait + // of, the bound's trait `did` then we can keep going, otherwise + // this is just a plain old equality bound. + if !trait_is_same_or_supertrait(cx, did, trait_did) { + return false + } + let last = path.segments.last_mut().unwrap(); + match last.params { + PP::AngleBracketed { ref mut bindings, .. } => { + bindings.push(clean::TypeBinding { + name: name.clone(), + ty: rhs.clone(), + }); + } + PP::Parenthesized { ref mut output, .. } => { + assert!(output.is_none()); + *output = Some(rhs.clone()); + } + }; + true + }) + }); + + // And finally, let's reassemble everything + let mut clauses = Vec::new(); + clauses.extend(lifetimes.into_iter().map(|(lt, bounds)| { + WP::RegionPredicate { lifetime: lt, bounds: bounds } + })); + clauses.extend(params.into_iter().map(|(k, v)| { + WP::BoundPredicate { + ty: clean::Generic(k), + bounds: v, + } + })); + clauses.extend(tybounds.into_iter().map(|(ty, bounds)| { + WP::BoundPredicate { ty: ty, bounds: bounds } + })); + clauses.extend(equalities.into_iter().map(|(lhs, rhs)| { + WP::EqPredicate { lhs: lhs, rhs: rhs } + })); + clauses +} + +pub fn ty_params(mut params: Vec) -> Vec { + for param in params.iter_mut() { + param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new())); + } + return params; +} + +fn ty_bounds(bounds: Vec) -> Vec { + bounds +} + +fn trait_is_same_or_supertrait(cx: &DocContext, child: ast::DefId, + trait_: ast::DefId) -> bool { + if child == trait_ { + return true + } + let def = ty::lookup_trait_def(cx.tcx(), child); + let predicates = ty::lookup_predicates(cx.tcx(), child); + let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + match *pred { + clean::WherePredicate::BoundPredicate { + ty: clean::Generic(ref s), + ref bounds + } if *s == "Self" => Some(bounds), + _ => None, + } + }).flat_map(|bounds| bounds.iter()).any(|bound| { + let poly_trait = match *bound { + clean::TraitBound(ref t, _) => t, + _ => return false, + }; + match poly_trait.trait_ { + clean::ResolvedPath { did, .. } => { + trait_is_same_or_supertrait(cx, did, trait_) + } + _ => false, + } + }) +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 113a622b07..a637ba9f29 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -75,7 +75,6 @@ pub struct CrateAnalysis { pub exported_items: privacy::ExportedItems, pub public_items: privacy::PublicItems, pub external_paths: ExternalPaths, - pub external_traits: RefCell>>, pub external_typarams: RefCell>>, pub inlined: RefCell>>, } @@ -155,7 +154,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, exported_items: exported_items, public_items: public_items, external_paths: RefCell::new(None), - external_traits: RefCell::new(None), external_typarams: RefCell::new(None), inlined: RefCell::new(None), }; @@ -168,8 +166,6 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, let external_paths = ctxt.external_paths.borrow_mut().take(); *analysis.external_paths.borrow_mut() = external_paths; - let map = ctxt.external_traits.borrow_mut().take(); - *analysis.external_traits.borrow_mut() = map; let map = ctxt.external_typarams.borrow_mut().take(); *analysis.external_typarams.borrow_mut() = map; let map = ctxt.inlined.borrow_mut().take(); diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index c6d8b9428c..862bca1b81 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -15,6 +15,7 @@ pub use self::TypeBound::*; use syntax; use syntax::codemap::Span; +use syntax::abi; use syntax::ast; use syntax::attr; use syntax::ast::{Ident, NodeId}; @@ -134,6 +135,7 @@ pub struct Function { pub unsafety: ast::Unsafety, pub whence: Span, pub generics: ast::Generics, + pub abi: abi::Abi, } pub struct Typedef { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index cdeeacfb78..0a1860c66f 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -9,7 +9,7 @@ // except according to those terms. use clean::*; -use std::iter::Extend; +use std::collections::HashMap; use std::mem::{replace, swap}; pub trait DocFolder : Sized { @@ -80,6 +80,13 @@ pub trait DocFolder : Sized { c.module = match replace(&mut c.module, None) { Some(module) => self.fold_item(module), None => None }; + let external_traits = replace(&mut c.external_traits, HashMap::new()); + c.external_traits = external_traits.into_iter().map(|(k, mut v)| { + let items = replace(&mut v.items, Vec::new()); + v.items = items.into_iter().filter_map(|i| self.fold_item(i)) + .collect(); + (k, v) + }).collect(); return c; } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ed37b973f7..d2dccca362 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,6 +18,7 @@ use std::fmt; use std::iter::repeat; +use syntax::abi::Abi; use syntax::ast; use syntax::ast_util; @@ -54,6 +55,7 @@ pub struct WhereClause<'a>(pub &'a clean::Generics); pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items pub struct CommaSep<'a, T: 'a>(pub &'a [T]); +pub struct AbiSpace(pub Abi); impl VisSpace { pub fn get(&self) -> Option { @@ -92,7 +94,7 @@ impl<'a> fmt::Display for TyParamBounds<'a> { impl fmt::Display for clean::Generics { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) } + if self.lifetimes.is_empty() && self.type_params.is_empty() { return Ok(()) } try!(f.write_str("<")); for (i, life) in self.lifetimes.iter().enumerate() { @@ -102,8 +104,8 @@ impl fmt::Display for clean::Generics { try!(write!(f, "{}", *life)); } - if self.type_params.len() > 0 { - if self.lifetimes.len() > 0 { + if !self.type_params.is_empty() { + if !self.lifetimes.is_empty() { try!(f.write_str(", ")); } for (i, tp) in self.type_params.iter().enumerate() { @@ -112,7 +114,7 @@ impl fmt::Display for clean::Generics { } try!(f.write_str(&tp.name)); - if tp.bounds.len() > 0 { + if !tp.bounds.is_empty() { try!(write!(f, ": {}", TyParamBounds(&tp.bounds))); } @@ -130,7 +132,7 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let &WhereClause(gens) = self; - if gens.where_predicates.len() == 0 { + if gens.where_predicates.is_empty() { return Ok(()); } try!(f.write_str(" where ")); @@ -173,7 +175,7 @@ impl fmt::Display for clean::Lifetime { impl fmt::Display for clean::PolyTrait { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.lifetimes.len() > 0 { + if !self.lifetimes.is_empty() { try!(f.write_str("for<")); for (i, lt) in self.lifetimes.iter().enumerate() { if i > 0 { @@ -210,7 +212,7 @@ impl fmt::Display for clean::PathParameters { clean::PathParameters::AngleBracketed { ref lifetimes, ref types, ref bindings } => { - if lifetimes.len() > 0 || types.len() > 0 || bindings.len() > 0 { + if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() { try!(f.write_str("<")); let mut comma = false; for lifetime in lifetimes { @@ -281,48 +283,46 @@ impl fmt::Display for clean::Path { } } +pub fn href(did: ast::DefId) -> Option<(String, ItemType, Vec)> { + let cache = cache(); + let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); + let &(ref fqp, shortty) = match cache.paths.get(&did) { + Some(p) => p, + None => return None, + }; + let mut url = if ast_util::is_local(did) || cache.inlined.contains(&did) { + repeat("../").take(loc.len()).collect::() + } else { + match cache.extern_locations[&did.krate] { + render::Remote(ref s) => s.to_string(), + render::Local => repeat("../").take(loc.len()).collect::(), + render::Unknown => return None, + } + }; + for component in &fqp[..fqp.len() - 1] { + url.push_str(component); + url.push_str("/"); + } + match shortty { + ItemType::Module => { + url.push_str(fqp.last().unwrap()); + url.push_str("/index.html"); + } + _ => { + url.push_str(shortty.to_static_str()); + url.push_str("."); + url.push_str(fqp.last().unwrap()); + url.push_str(".html"); + } + } + Some((url, shortty, fqp.to_vec())) +} + /// Used when rendering a `ResolvedPath` structure. This invokes the `path` /// rendering function with the necessary arguments for linking to a local path. -fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path, +fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, path: &clean::Path, print_all: bool) -> fmt::Result { - path(w, p, print_all, - |cache, loc| { - if ast_util::is_local(did) || cache.inlined.contains(&did) { - Some(repeat("../").take(loc.len()).collect::()) - } else { - match cache.extern_locations[&did.krate] { - render::Remote(ref s) => Some(s.to_string()), - render::Local => { - Some(repeat("../").take(loc.len()).collect::()) - } - render::Unknown => None, - } - } - }, - |cache| { - match cache.paths.get(&did) { - None => None, - Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty)) - } - }) -} - -fn path(w: &mut fmt::Formatter, - path: &clean::Path, - print_all: bool, - root: F, - info: G) - -> fmt::Result where - F: FnOnce(&render::Cache, &[String]) -> Option, - G: FnOnce(&render::Cache) -> Option<(Vec, ItemType)>, -{ - // The generics will get written to both the title and link let last = path.segments.last().unwrap(); - let generics = format!("{}", last.params); - - let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone()); - let cache = cache(); - let abs_root = root(&*cache, &loc); let rel_root = match &*path.segments[0].name { "self" => Some("./".to_string()), _ => None, @@ -334,8 +334,7 @@ fn path(w: &mut fmt::Formatter, Some(root) => { let mut root = String::from_str(&root); for seg in &path.segments[..amt] { - if "super" == seg.name || - "self" == seg.name { + if "super" == seg.name || "self" == seg.name { try!(write!(w, "{}::", seg.name)); } else { root.push_str(&seg.name); @@ -355,37 +354,14 @@ fn path(w: &mut fmt::Formatter, } } - match info(&*cache) { - // This is a documented path, link to it! - Some((ref fqp, shortty)) if abs_root.is_some() => { - let mut url = String::from_str(&abs_root.unwrap()); - let to_link = &fqp[..fqp.len() - 1]; - for component in to_link { - url.push_str(component); - url.push_str("/"); - } - match shortty { - ItemType::Module => { - url.push_str(fqp.last().unwrap()); - url.push_str("/index.html"); - } - _ => { - url.push_str(shortty.to_static_str()); - url.push_str("."); - url.push_str(fqp.last().unwrap()); - url.push_str(".html"); - } - } - + match href(did) { + Some((url, shortty, fqp)) => { try!(write!(w, "{}", shortty, url, fqp.connect("::"), last.name)); } - - _ => { - try!(write!(w, "{}", last.name)); - } + _ => try!(write!(w, "{}", last.name)), } - try!(write!(w, "{}", generics)); + try!(write!(w, "{}", last.params)); Ok(()) } @@ -491,7 +467,8 @@ impl fmt::Display for clean::Type { } clean::Bottom => f.write_str("!"), clean::RawPointer(m, ref t) => { - write!(f, "*{}{}", RawMutableSpace(m), **t) + primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer, + &format!("*{}{}", RawMutableSpace(m), **t)) } clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => { let lt = match *l { @@ -527,6 +504,29 @@ impl fmt::Display for clean::Type { } Ok(()) } + // It's pretty unsightly to look at `::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + clean::QPath { + ref name, + ref self_type, + trait_: box clean::ResolvedPath { did, ref typarams, .. }, + } => { + try!(write!(f, "{}::", self_type)); + let path = clean::Path::singleton(name.clone()); + try!(resolved_path(f, did, &path, false)); + + // FIXME: `typarams` are not rendered, and this seems bad? + drop(typarams); + Ok(()) + } clean::QPath { ref name, ref self_type, ref trait_ } => { write!(f, "<{} as {}>::{}", self_type, trait_, name) } @@ -541,7 +541,7 @@ impl fmt::Display for clean::Arguments { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, input) in self.values.iter().enumerate() { if i > 0 { try!(write!(f, ", ")); } - if input.name.len() > 0 { + if !input.name.is_empty() { try!(write!(f, "{}: ", input.name)); } try!(write!(f, "{}", input.type_)); @@ -585,8 +585,8 @@ impl<'a> fmt::Display for Method<'a> { } } for (i, input) in d.inputs.values.iter().enumerate() { - if i > 0 || args.len() > 0 { args.push_str(", "); } - if input.name.len() > 0 { + if i > 0 || !args.is_empty() { args.push_str(", "); } + if !input.name.is_empty() { args.push_str(&format!("{}: ", input.name)); } args.push_str(&format!("{}", input.type_)); @@ -661,17 +661,7 @@ impl fmt::Display for clean::ViewListIdent { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.source { Some(did) => { - let path = clean::Path { - global: false, - segments: vec!(clean::PathSegment { - name: self.name.clone(), - params: clean::PathParameters::AngleBracketed { - lifetimes: Vec::new(), - types: Vec::new(), - bindings: Vec::new() - } - }) - }; + let path = clean::Path::singleton(self.name.clone()); resolved_path(f, did, &path, false) } _ => write!(f, "{}", self.name), @@ -703,6 +693,16 @@ impl fmt::Display for RawMutableSpace { } } +impl fmt::Display for AbiSpace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + Abi::Rust => Ok(()), + Abi::C => write!(f, "extern "), + abi => write!(f, "extern {} ", abi), + } + } +} + impl<'a> fmt::Display for Stability<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Stability(stab) = *self; @@ -734,7 +734,7 @@ impl<'a> fmt::Display for ConciseStability<'a> { }; write!(f, "", lvl = Escape(&*lvl), - colon = if stability.reason.len() > 0 { ": " } else { "" }, + colon = if !stability.reason.is_empty() { ": " } else { "" }, reason = Escape(&*stability.reason)) } None => { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 3acd17dedd..a53884ca04 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -130,7 +130,7 @@ r##" content = *t, root_path = page.root_path, ty = page.ty, - logo = if layout.logo.len() == 0 { + logo = if layout.logo.is_empty() { "".to_string() } else { format!("\ @@ -141,7 +141,7 @@ r##" title = page.title, description = page.description, keywords = page.keywords, - favicon = if layout.favicon.len() == 0 { + favicon = if layout.favicon.is_empty() { "".to_string() } else { format!(r#""#, layout.favicon) @@ -152,7 +152,7 @@ r##" sidebar = *sidebar, krate = layout.krate, play_url = layout.playground_url, - play_js = if layout.playground_url.len() == 0 { + play_js = if layout.playground_url.is_empty() { "".to_string() } else { format!(r#""#, page.root_path) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index afc434eb2d..334f05fb36 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -29,9 +29,10 @@ use libc; use std::ascii::AsciiExt; -use std::ffi::CString; use std::cell::RefCell; use std::collections::HashMap; +use std::default::Default; +use std::ffi::CString; use std::fmt; use std::slice; use std::str; @@ -72,6 +73,9 @@ type blockcodefn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, type headerfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, libc::c_int, *mut libc::c_void); +type codespanfn = extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer, + *mut libc::c_void); + type linkfn = extern "C" fn (*mut hoedown_buffer, *const hoedown_buffer, *const hoedown_buffer, *const hoedown_buffer, *mut libc::c_void) -> libc::c_int; @@ -89,11 +93,12 @@ struct hoedown_renderer { blockhtml: Option, header: Option, - other_block_level_callbacks: [libc::size_t; 9], /* span level callbacks - NULL or return 0 prints the span verbatim */ - other_span_level_callbacks_1: [libc::size_t; 9], + autolink: libc::size_t, // unused + codespan: Option, + other_span_level_callbacks_1: [libc::size_t; 7], link: Option, other_span_level_callbacks_2: [libc::size_t; 5], // hoedown will add `math` callback here, but we use an old version of it. @@ -178,13 +183,25 @@ impl hoedown_buffer { /// left as-is.) fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { let trimmed = s.trim(); - if trimmed.starts_with("# ") { + if trimmed == "#" { + Some("") + } else if trimmed.starts_with("# ") { Some(&trimmed[2..]) } else { None } } +/// Returns a new string with all consecutive whitespace collapsed into +/// single spaces. +/// +/// Any leading or trailing whitespace will be trimmed. +fn collapse_whitespace(s: &str) -> String { + s.split(|c: char| c.is_whitespace()).filter(|s| { + !s.is_empty() + }).collect::>().connect(" ") +} + thread_local!(static USED_HEADER_MAP: RefCell> = { RefCell::new(HashMap::new()) }); @@ -230,7 +247,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { stripped_filtered_line(l).unwrap_or(l) }).collect::>().connect("\n"); let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, false, true); + let test = test::maketest(&test, krate, false, + &Default::default()); s.push_str(&format!("{}", Escape(&test))); }); s.push_str(&highlight::highlight(&text, @@ -287,7 +305,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { let text = format!(r##"{sec}{}"##, s, lvl = level, id = id, - sec = if sec.len() == 0 { + sec = if sec.is_empty() { sec.to_string() } else { format!("{} ", sec) @@ -299,6 +317,20 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { reset_headers(); + extern fn codespan(ob: *mut hoedown_buffer, text: *const hoedown_buffer, _: *mut libc::c_void) { + let content = if text.is_null() { + "".to_string() + } else { + let bytes = unsafe { (*text).as_bytes() }; + let s = str::from_utf8(bytes).unwrap(); + collapse_whitespace(s) + }; + + let content = format!("{}", Escape(&content)); + let element = CString::new(content).unwrap(); + unsafe { hoedown_buffer_puts(ob, element.as_ptr()); } + } + unsafe { let ob = hoedown_buffer_new(DEF_OUNIT); let renderer = hoedown_html_renderer_new(0, 0); @@ -310,6 +342,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { = &mut opaque as *mut _ as *mut libc::c_void; (*renderer).blockcode = Some(block); (*renderer).header = Some(header); + (*renderer).codespan = Some(codespan); let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16); hoedown_document_render(document, ob, s.as_ptr(), @@ -458,7 +491,7 @@ impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let Markdown(md) = *self; // This is actually common enough to special-case - if md.len() == 0 { return Ok(()) } + if md.is_empty() { return Ok(()) } render(fmt, md, false) } } @@ -523,7 +556,7 @@ pub fn plain_summary_line(md: &str) -> String { #[cfg(test)] mod tests { use super::{LangString, Markdown}; - use super::plain_summary_line; + use super::{collapse_whitespace, plain_summary_line}; #[test] fn test_lang_string_parse() { @@ -571,4 +604,18 @@ mod tests { t("# top header", "top header"); t("## header", "header"); } + + #[test] + fn test_collapse_whitespace() { + fn t(input: &str, expected: &str) { + let actual = collapse_whitespace(input); + assert_eq!(actual, expected); + } + + t("foo", "foo"); + t("foo bar baz", "foo bar baz"); + t(" foo bar", "foo bar"); + t("\tfoo bar\nbaz", "foo bar baz"); + t("foo bar \n baz\t\tqux\n", "foo bar baz qux"); + } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index ac097d051b..5f4a3e74b6 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -44,6 +44,7 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter, BufReader}; use std::iter::repeat; +use std::mem; use std::path::{PathBuf, Path}; use std::str; use std::sync::Arc; @@ -61,7 +62,7 @@ use clean; use doctree; use fold::DocFolder; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability}; -use html::format::{ConciseStability, TyParamBounds, WhereClause}; +use html::format::{ConciseStability, TyParamBounds, WhereClause, href, AbiSpace}; use html::highlight; use html::item_type::ItemType; use html::layout; @@ -136,6 +137,14 @@ pub struct Impl { pub stability: Option, } +impl Impl { + fn trait_did(&self) -> Option { + self.impl_.trait_.as_ref().and_then(|tr| { + if let clean::ResolvedPath { did, .. } = *tr {Some(did)} else {None} + }) + } +} + /// This cache is used to store information about the `clean::Crate` being /// rendered in order to provide more useful documentation. This contains /// information like all implementors of a trait, all traits a type implements, @@ -276,7 +285,9 @@ impl fmt::Display for IndexItemFunctionType { return write!(f, "null") } - let inputs: Vec = self.inputs.iter().map(|ref t| format!("{}", t)).collect(); + let inputs: Vec = self.inputs.iter().map(|ref t| { + format!("{}", t) + }).collect(); try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.connect(","))); match self.output { @@ -383,9 +394,7 @@ pub fn run(mut krate: clean::Crate, privmod: false, public_items: public_items, orphan_methods: Vec::new(), - traits: analysis.as_ref().map(|a| { - a.external_traits.borrow_mut().take().unwrap() - }).unwrap_or(HashMap::new()), + traits: mem::replace(&mut krate.external_traits, HashMap::new()), typarams: analysis.as_ref().map(|a| { a.external_typarams.borrow_mut().take().unwrap() }).unwrap_or(HashMap::new()), @@ -903,7 +912,7 @@ impl DocFolder for Cache { false) } clean::MethodItem(..) => { - if self.parent_stack.len() == 0 { + if self.parent_stack.is_empty() { ((None, None), false) } else { let last = self.parent_stack.last().unwrap(); @@ -911,9 +920,10 @@ impl DocFolder for Cache { let path = match self.paths.get(&did) { Some(&(_, ItemType::Trait)) => Some(&self.stack[..self.stack.len() - 1]), - // The current stack not necessarily has correlation for - // where the type was defined. On the other hand, - // `paths` always has the right information if present. + // The current stack not necessarily has correlation + // for where the type was defined. On the other + // hand, `paths` always has the right + // information if present. Some(&(ref fqp, ItemType::Struct)) | Some(&(ref fqp, ItemType::Enum)) => Some(&fqp[..fqp.len() - 1]), @@ -963,7 +973,7 @@ impl DocFolder for Cache { // Keep track of the fully qualified path for this item. let pushed = if item.name.is_some() { let n = item.name.as_ref().unwrap(); - if n.len() > 0 { + if !n.is_empty() { self.stack.push(n.to_string()); true } else { false } @@ -1015,7 +1025,16 @@ impl DocFolder for Cache { self.parent_stack.push(did); true } - _ => false + ref t => { + match t.primitive_type() { + Some(prim) => { + let did = ast_util::local_def(prim.to_node_id()); + self.parent_stack.push(did); + true + } + _ => false, + } + } } } _ => false @@ -1027,10 +1046,6 @@ impl DocFolder for Cache { Some(item) => { match item { clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { - use clean::{Primitive, Vector, ResolvedPath, BorrowedRef}; - use clean::PrimitiveType::{Array, Slice, PrimitiveTuple}; - use clean::{FixedVector, Tuple}; - // extract relevant documentation for this impl let dox = match attrs.into_iter().find(|a| { match *a { @@ -1048,37 +1063,18 @@ impl DocFolder for Cache { // Figure out the id of this impl. This may map to a // primitive rather than always to a struct/enum. let did = match i.for_ { - ResolvedPath { did, .. } => Some(did), - - // References to primitives are picked up as well to - // recognize implementations for &str, this may not - // be necessary in a DST world. - Primitive(p) | - BorrowedRef { type_: box Primitive(p), ..} => - { - Some(ast_util::local_def(p.to_node_id())) + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + Some(did) } - FixedVector(..) | - BorrowedRef { type_: box FixedVector(..), .. } => - { - Some(ast_util::local_def(Array.to_node_id())) + ref t => { + t.primitive_type().map(|p| { + ast_util::local_def(p.to_node_id()) + }) } - - // In a DST world, we may only need Vector, but for now we - // also pick up borrowed references - Vector(..) | - BorrowedRef{ type_: box Vector(..), .. } => - { - Some(ast_util::local_def(Slice.to_node_id())) - } - - Tuple(..) => { - let id = PrimitiveTuple.to_node_id(); - Some(ast_util::local_def(id)) - } - - _ => None, }; if let Some(did) = did { @@ -1119,7 +1115,7 @@ impl Context { fn recurse(&mut self, s: String, f: F) -> T where F: FnOnce(&mut Context) -> T, { - if s.len() == 0 { + if s.is_empty() { panic!("Unexpected empty destination: {:?}", self.current); } let prev = self.dst.clone(); @@ -1212,7 +1208,7 @@ impl Context { let mut title = cx.current.connect("::"); if pushname { - if title.len() > 0 { + if !title.is_empty() { title.push_str("::"); } title.push_str(it.name.as_ref().unwrap()); @@ -1347,7 +1343,9 @@ impl Context { fn ignore_private_item(&self, it: &clean::Item) -> bool { match it.inner { clean::ModuleItem(ref m) => { - (m.items.len() == 0 && it.doc_value().is_none()) || + (m.items.is_empty() && + it.doc_value().is_none() && + it.visibility != Some(ast::Public)) || (self.passes.contains("strip-private") && it.visibility != Some(ast::Public)) } clean::PrimitiveItem(..) => it.visibility != Some(ast::Public), @@ -1692,7 +1690,7 @@ struct Initializer<'a>(&'a str); impl<'a> fmt::Display for Initializer<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let Initializer(s) = *self; - if s.len() == 0 { return Ok(()); } + if s.is_empty() { return Ok(()); } try!(write!(f, " = ")); write!(f, "{}", s) } @@ -1723,10 +1721,11 @@ fn item_static(w: &mut fmt::Formatter, it: &clean::Item, fn item_function(w: &mut fmt::Formatter, it: &clean::Item, f: &clean::Function) -> fmt::Result { - try!(write!(w, "
{vis}{unsafety}fn \
+    try!(write!(w, "
{vis}{unsafety}{abi}fn \
                     {name}{generics}{decl}{where_clause}
", vis = VisSpace(it.visibility), unsafety = UnsafetySpace(f.unsafety), + abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, where_clause = WhereClause(&f.generics), @@ -1737,8 +1736,8 @@ fn item_function(w: &mut fmt::Formatter, it: &clean::Item, fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); - if t.bounds.len() > 0 { - if bounds.len() > 0 { + if !t.bounds.is_empty() { + if !bounds.is_empty() { bounds.push(' '); } bounds.push_str(": "); @@ -1767,29 +1766,29 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, match m.inner { clean::MethodItem(_) => true, _ => false } }).collect::>(); - if t.items.len() == 0 { + if t.items.is_empty() { try!(write!(w, "{{ }}")); } else { try!(write!(w, "{{\n")); for t in &types { try!(write!(w, " ")); - try!(render_method(w, t)); + try!(render_method(w, t, MethodLink::Anchor)); try!(write!(w, ";\n")); } - if types.len() > 0 && required.len() > 0 { + if !types.is_empty() && !required.is_empty() { try!(w.write_str("\n")); } for m in &required { try!(write!(w, " ")); - try!(render_method(w, m)); + try!(render_method(w, m, MethodLink::Anchor)); try!(write!(w, ";\n")); } - if required.len() > 0 && provided.len() > 0 { + if !required.is_empty() && !provided.is_empty() { try!(w.write_str("\n")); } for m in &provided { try!(write!(w, " ")); - try!(render_method(w, m)); + try!(render_method(w, m, MethodLink::Anchor)); try!(write!(w, " {{ ... }}\n")); } try!(write!(w, "}}")); @@ -1805,13 +1804,13 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, shortty(m), *m.name.as_ref().unwrap(), ConciseStability(&m.stability))); - try!(render_method(w, m)); + try!(render_method(w, m, MethodLink::Anchor)); try!(write!(w, "")); try!(document(w, m)); Ok(()) } - if types.len() > 0 { + if !types.is_empty() { try!(write!(w, "

Associated Types

@@ -1823,7 +1822,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } // Output the documentation for each function individually - if required.len() > 0 { + if !required.is_empty() { try!(write!(w, "

Required Methods

@@ -1833,7 +1832,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } try!(write!(w, "
")); } - if provided.len() > 0 { + if !provided.is_empty() { try!(write!(w, "

Provided Methods

@@ -1844,6 +1843,9 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "
")); } + // If there are methods directly on this trait object, render them here. + try!(render_methods(w, it)); + let cache = cache(); try!(write!(w, "

Implementors

@@ -1880,7 +1882,7 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, default: &Option) -> fmt::Result { try!(write!(w, "type {}", it.name.as_ref().unwrap())); - if bounds.len() > 0 { + if !bounds.is_empty() { try!(write!(w, ": {}", TyParamBounds(bounds))) } if let Some(ref default) = *default { @@ -1889,14 +1891,23 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, Ok(()) } -fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result { +fn render_method(w: &mut fmt::Formatter, meth: &clean::Item, + link: MethodLink) -> fmt::Result { fn method(w: &mut fmt::Formatter, it: &clean::Item, unsafety: ast::Unsafety, abi: abi::Abi, g: &clean::Generics, selfty: &clean::SelfTy, - d: &clean::FnDecl) -> fmt::Result { + d: &clean::FnDecl, link: MethodLink) -> fmt::Result { use syntax::abi::Abi; - write!(w, "{}{}fn {name}\ + let name = it.name.as_ref().unwrap(); + let anchor = format!("#{}.{}", shortty(it), name); + let href = match link { + MethodLink::Anchor => anchor, + MethodLink::GotoSource(did) => { + href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor) + } + }; + write!(w, "{}{}fn {name}\ {generics}{decl}{where_clause}", match unsafety { ast::Unsafety::Unsafe => "unsafe ", @@ -1906,18 +1917,20 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result { Abi::Rust => String::new(), a => format!("extern {} ", a.to_string()) }, - ty = shortty(it), - name = it.name.as_ref().unwrap(), + href = href, + name = name, generics = *g, decl = Method(selfty, d), where_clause = WhereClause(g)) } match meth.inner { clean::TyMethodItem(ref m) => { - method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl) + method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl, + link) } clean::MethodItem(ref m) => { - method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl) + method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl, + link) } clean::AssociatedTypeItem(ref bounds, ref default) => { assoc_type(w, meth, bounds, default) @@ -1973,7 +1986,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, it.name.as_ref().unwrap(), e.generics, WhereClause(&e.generics))); - if e.variants.len() == 0 && !e.variants_stripped { + if e.variants.is_empty() && !e.variants_stripped { try!(write!(w, " {{}}")); } else { try!(write!(w, " {{\n")); @@ -2018,7 +2031,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "
")); try!(document(w, it)); - if e.variants.len() > 0 { + if !e.variants.is_empty() { try!(write!(w, "

Variants

\n")); for variant in &e.variants { try!(write!(w, "
{stab}{name}", @@ -2144,69 +2157,73 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, Ok(()) } +#[derive(Copy, Clone)] +enum MethodLink { + Anchor, + GotoSource(ast::DefId), +} + fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { - match cache().impls.get(&it.def_id) { - Some(v) => { - let (non_trait, traits): (Vec<_>, _) = v.iter().cloned() - .partition(|i| i.impl_.trait_.is_none()); - if non_trait.len() > 0 { - try!(write!(w, "

Methods

")); - for i in &non_trait { - try!(render_impl(w, i)); - } - } - if traits.len() > 0 { - try!(write!(w, "

Trait \ - Implementations

")); - let (derived, manual): (Vec<_>, _) = traits.into_iter() - .partition(|i| i.impl_.derived); - for i in &manual { - try!(render_impl(w, i)); - } - if derived.len() > 0 { - try!(write!(w, "

Derived Implementations \ -

")); - for i in &derived { - try!(render_impl(w, i)); - } - } + let v = match cache().impls.get(&it.def_id) { + Some(v) => v.clone(), + None => return Ok(()), + }; + let (non_trait, traits): (Vec<_>, _) = v.into_iter() + .partition(|i| i.impl_.trait_.is_none()); + if !non_trait.is_empty() { + try!(write!(w, "

Methods

")); + for i in &non_trait { + try!(render_impl(w, i, MethodLink::Anchor)); + } + } + if !traits.is_empty() { + try!(write!(w, "

Trait \ + Implementations

")); + let (derived, manual): (Vec<_>, _) = traits.into_iter() + .partition(|i| i.impl_.derived); + for i in &manual { + let did = i.trait_did().unwrap(); + try!(render_impl(w, i, MethodLink::GotoSource(did))); + } + if !derived.is_empty() { + try!(write!(w, "

\ + Derived Implementations \ +

")); + for i in &derived { + let did = i.trait_did().unwrap(); + try!(render_impl(w, i, MethodLink::GotoSource(did))); } } - None => {} } Ok(()) } -fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result { +fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink) + -> fmt::Result { try!(write!(w, "

{}impl{} ", ConciseStability(&i.stability), i.impl_.generics)); - match i.impl_.polarity { - Some(clean::ImplPolarity::Negative) => try!(write!(w, "!")), - _ => {} + if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity { + try!(write!(w, "!")); } - match i.impl_.trait_ { - Some(ref ty) => try!(write!(w, "{} for ", *ty)), - None => {} + if let Some(ref ty) = i.impl_.trait_ { + try!(write!(w, "{} for ", *ty)); } - try!(write!(w, "{}{}

", i.impl_.for_, WhereClause(&i.impl_.generics))); - match i.dox { - Some(ref dox) => { - try!(write!(w, "
{}
", - Markdown(dox))); - } - None => {} + try!(write!(w, "{}{}", i.impl_.for_, + WhereClause(&i.impl_.generics))); + if let Some(ref dox) = i.dox { + try!(write!(w, "
{}
", Markdown(dox))); } - fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool) - -> fmt::Result { + fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, + dox: bool, link: MethodLink) -> fmt::Result { match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { try!(write!(w, "

{}", *item.name.as_ref().unwrap(), shortty(item), ConciseStability(&item.stability))); - try!(render_method(w, item)); + try!(render_method(w, item, link)); try!(write!(w, "

\n")); } clean::TypedefItem(ref tydef) => { @@ -2239,11 +2256,12 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result { } try!(write!(w, "
")); - for trait_item in &i.impl_.items { - try!(doctraititem(w, trait_item, true)); + for trait_item in i.impl_.items.iter() { + try!(doctraititem(w, trait_item, true, link)); } fn render_default_methods(w: &mut fmt::Formatter, + did: ast::DefId, t: &clean::Trait, i: &clean::Impl) -> fmt::Result { for trait_item in &t.items { @@ -2253,7 +2271,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result { None => {} } - try!(doctraititem(w, trait_item, false)); + try!(doctraititem(w, trait_item, false, + MethodLink::GotoSource(did))); } Ok(()) } @@ -2262,17 +2281,10 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result { // default methods which weren't overridden in the implementation block. // FIXME: this also needs to be done for associated types, whenever defaults // for them work. - match i.impl_.trait_ { - Some(clean::ResolvedPath { did, .. }) => { - try!({ - match cache().traits.get(&did) { - Some(t) => try!(render_default_methods(w, t, &i.impl_)), - None => {} - } - Ok(()) - }) + if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ { + if let Some(t) = cache().traits.get(&did) { + try!(render_default_methods(w, did, t, &i.impl_)); } - Some(..) | None => {} } try!(write!(w, "
")); Ok(()) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index ca6d944195..c3ab375a9e 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -78,9 +78,11 @@ return; } - if (e.which === 191 && $('#help').hasClass('hidden')) { // question mark - e.preventDefault(); - $('#help').removeClass('hidden'); + if (e.which === 191) { // question mark + if (e.shiftKey && $('#help').hasClass('hidden')) { + e.preventDefault(); + $('#help').removeClass('hidden'); + } } else if (e.which === 27) { // esc if (!$('#help').hasClass('hidden')) { e.preventDefault(); @@ -468,6 +470,8 @@ if ($active.length) { document.location.href = $active.find('a').prop('href'); } + } else { + $active.removeClass('highlighted'); } }); } @@ -713,10 +717,12 @@ if (crates[i] == window.currentCrate) { klass += ' current'; } - var desc = rawSearchIndex[crates[i]].items[0][3]; - div.append($('', {'href': '../' + crates[i] + '/index.html', - 'title': plainSummaryLine(desc), - 'class': klass}).text(crates[i])); + if (rawSearchIndex[crates[i]].items[0]) { + var desc = rawSearchIndex[crates[i]].items[0][3]; + div.append($('', {'href': '../' + crates[i] + '/index.html', + 'title': plainSummaryLine(desc), + 'class': klass}).text(crates[i])); + } } sidebar.append(div); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d1dcfc2600..008da466db 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -130,10 +130,10 @@ struct Output { pub fn main() { const STACK_SIZE: usize = 32000000; // 32MB - let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || { + let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || { let s = env::args().collect::>(); main_args(&s) - }).unwrap().join(); + }).unwrap().join().unwrap(); env::set_exit_status(res as i32); } @@ -154,8 +154,9 @@ pub fn opts() -> Vec { optmulti("", "cfg", "pass a --cfg to rustc", ""), optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH"), optmulti("", "plugin-path", "directory to load plugins from", "DIR"), - optmulti("", "passes", "space separated list of passes to also run, a \ - value of `list` will print available passes", + optmulti("", "passes", "list of passes to also run, you might want \ + to pass it multiple times; a value of `list` \ + will print available passes", "PASSES"), optmulti("", "plugins", "space separated list of plugins to also load", "PLUGINS"), @@ -218,7 +219,7 @@ pub fn main_args(args: &[String]) -> isize { return 0; } - if matches.free.len() == 0 { + if matches.free.is_empty() { println!("expected an input file to act on"); return 1; } if matches.free.len() > 1 { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index a84da60b01..00de4e3ec5 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::default::Default; use std::fs::File; -use std::io; use std::io::prelude::*; +use std::io; use std::path::{PathBuf, Path}; use core; @@ -23,7 +24,7 @@ use externalfiles::ExternalHtml; use html::escape::Escape; use html::markdown; use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, reset_headers}; -use test::Collector; +use test::{TestOptions, Collector}; /// Separate any lines at the start of the file that begin with `%`. fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { @@ -58,7 +59,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let input_str = load_or_return!(input, 1, 2); let playground = matches.opt_str("markdown-playground-url"); if playground.is_some() { - markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = None; }); + markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); }); } let playground = playground.unwrap_or("".to_string()); @@ -73,7 +74,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, }; let (metadata, text) = extract_leading_metadata(&input_str); - if metadata.len() == 0 { + if metadata.is_empty() { let _ = writeln!(&mut io::stderr(), "invalid markdown file: expecting initial line with `% ...TITLE...`"); return 5; @@ -143,7 +144,10 @@ pub fn test(input: &str, libs: SearchPaths, externs: core::Externs, mut test_args: Vec) -> isize { let input_str = load_or_return!(input, 1, 2); - let mut collector = Collector::new(input.to_string(), libs, externs, true, false); + let mut opts = TestOptions::default(); + opts.no_crate_inject = true; + let mut collector = Collector::new(input.to_string(), libs, externs, + true, opts); find_testable_code(&input_str, &mut collector); test_args.insert(0, "rustdoctest".to_string()); testing::test_main(&test_args, collector.tests); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 953b442bb3..53cfbb3efd 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -215,9 +215,9 @@ impl<'a> fold::DocFolder for Stripper<'a> { match i.inner { // emptied modules/impls have no need to exist clean::ModuleItem(ref m) - if m.items.len() == 0 && + if m.items.is_empty() && i.doc_value().is_none() => None, - clean::ImplItem(ref i) if i.items.len() == 0 => None, + clean::ImplItem(ref i) if i.items.is_empty() => None, _ => { self.retained.insert(i.def_id.node); Some(i) @@ -294,7 +294,7 @@ pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult { &clean::NameValue(ref x, _) if "doc" == *x => false, _ => true }).cloned().collect(); - if docstr.len() > 0 { + if !docstr.is_empty() { a.push(clean::NameValue("doc".to_string(), docstr)); } i.attrs = a; @@ -350,7 +350,7 @@ pub fn unindent(s: &str) -> String { } }); - if lines.len() >= 1 { + if !lines.is_empty() { let mut unindented = vec![ lines[0].trim().to_string() ]; unindented.push_all(&lines.tail().iter().map(|&line| { if line.chars().all(|c| c.is_whitespace()) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f5bee6240d..449f9c79d1 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -38,6 +38,12 @@ use html::markdown; use passes; use visit_ast::RustdocVisitor; +#[derive(Clone, Default)] +pub struct TestOptions { + pub no_crate_inject: bool, + pub attrs: Vec, +} + pub fn run(input: &str, cfgs: Vec, libs: SearchPaths, @@ -75,7 +81,7 @@ pub fn run(input: &str, "rustdoc-test", None) .expect("phase_2_configure_and_expand aborted in rustdoc!"); - let inject_crate = should_inject_crate(&krate); + let opts = scrape_test_config(&krate); let ctx = core::DocContext { krate: &krate, @@ -102,7 +108,7 @@ pub fn run(input: &str, libs, externs, false, - inject_crate); + opts); collector.fold_crate(krate); test_args.insert(0, "rustdoctest".to_string()); @@ -113,41 +119,44 @@ pub fn run(input: &str, } // Look for #![doc(test(no_crate_inject))], used by crates in the std facade -fn should_inject_crate(krate: &::syntax::ast::Crate) -> bool { +fn scrape_test_config(krate: &::syntax::ast::Crate) -> TestOptions { use syntax::attr::AttrMetaMethods; + use syntax::print::pprust; - let mut inject_crate = true; - - for attr in &krate.attrs { - if attr.check_name("doc") { - for list in attr.meta_item_list().into_iter() { - for attr in list { - if attr.check_name("test") { - for list in attr.meta_item_list().into_iter() { - for attr in list { - if attr.check_name("no_crate_inject") { - inject_crate = false; - } - } - } - } + let mut opts = TestOptions { + no_crate_inject: false, + attrs: Vec::new(), + }; + + let attrs = krate.attrs.iter().filter(|a| a.check_name("doc")) + .filter_map(|a| a.meta_item_list()) + .flat_map(|l| l.iter()) + .filter(|a| a.check_name("test")) + .filter_map(|a| a.meta_item_list()) + .flat_map(|l| l.iter()); + for attr in attrs { + if attr.check_name("no_crate_inject") { + opts.no_crate_inject = true; + } + if attr.check_name("attr") { + if let Some(l) = attr.meta_item_list() { + for item in l { + opts.attrs.push(pprust::meta_item_to_string(item)); } } } } - return inject_crate; + return opts; } -#[allow(deprecated)] fn runtest(test: &str, cratename: &str, libs: SearchPaths, externs: core::Externs, should_panic: bool, no_run: bool, as_test_harness: bool, - inject_crate: bool) { + opts: &TestOptions) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` - let test = maketest(test, Some(cratename), true, as_test_harness, - inject_crate); + let test = maketest(test, Some(cratename), as_test_harness, opts); let input = config::Input::Str(test.to_string()); let sessopts = config::Options { @@ -250,8 +259,8 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, } } -pub fn maketest(s: &str, cratename: Option<&str>, lints: bool, - dont_insert_main: bool, inject_crate: bool) -> String { +pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, + opts: &TestOptions) -> String { let (crate_attrs, everything_else) = partition_source(s); let mut prog = String::new(); @@ -260,20 +269,18 @@ pub fn maketest(s: &str, cratename: Option<&str>, lints: bool, // are intended to be crate attributes. prog.push_str(&crate_attrs); - if lints { - prog.push_str(r" -#![allow(unused_variables, unused_assignments, unused_mut, unused_attributes, dead_code)] -"); + // Next, any attributes for other aspects such as lints. + for attr in &opts.attrs { + prog.push_str(&format!("#![{}]\n", attr)); } // Don't inject `extern crate std` because it's already injected by the // compiler. - if !s.contains("extern crate") && inject_crate { + if !s.contains("extern crate") && !opts.no_crate_inject { match cratename { Some(cratename) => { if s.contains(cratename) { - prog.push_str(&format!("extern crate {};\n", - cratename)); + prog.push_str(&format!("extern crate {};\n", cratename)); } } None => {} @@ -325,12 +332,12 @@ pub struct Collector { use_headers: bool, current_header: Option, cratename: String, - inject_crate: bool + opts: TestOptions, } impl Collector { pub fn new(cratename: String, libs: SearchPaths, externs: core::Externs, - use_headers: bool, inject_crate: bool) -> Collector { + use_headers: bool, opts: TestOptions) -> Collector { Collector { tests: Vec::new(), names: Vec::new(), @@ -340,7 +347,7 @@ impl Collector { use_headers: use_headers, current_header: None, cratename: cratename, - inject_crate: inject_crate + opts: opts, } } @@ -357,13 +364,14 @@ impl Collector { let libs = self.libs.clone(); let externs = self.externs.clone(); let cratename = self.cratename.to_string(); - let inject_crate = self.inject_crate; + let opts = self.opts.clone(); debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { name: testing::DynTestName(name), ignore: should_ignore, - should_panic: testing::ShouldPanic::No, // compiler failures are test failures + // compiler failures are test failures + should_panic: testing::ShouldPanic::No, }, testfn: testing::DynTestFn(Box::new(move|| { runtest(&test, @@ -373,7 +381,7 @@ impl Collector { should_panic, no_run, as_test_harness, - inject_crate); + &opts); })) }); } @@ -401,7 +409,7 @@ impl Collector { impl DocFolder for Collector { fn fold_item(&mut self, item: clean::Item) -> Option { let pushed = match item.name { - Some(ref name) if name.len() == 0 => false, + Some(ref name) if name.is_empty() => false, Some(ref name) => { self.names.push(name.to_string()); true } None => false }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3f813b30ec..e4f4dbaafb 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -12,6 +12,7 @@ //! usable for clean use std::collections::HashSet; +use std::mem; use syntax::abi; use syntax::ast; @@ -40,6 +41,7 @@ pub struct RustdocVisitor<'a, 'tcx: 'a> { pub cx: &'a core::DocContext<'tcx>, pub analysis: Option<&'a core::CrateAnalysis>, view_item_stack: HashSet, + inlining_from_glob: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -54,6 +56,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { cx: cx, analysis: analysis, view_item_stack: stack, + inlining_from_glob: false, } } @@ -120,7 +123,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn visit_fn(&mut self, item: &ast::Item, name: ast::Ident, fd: &ast::FnDecl, - unsafety: &ast::Unsafety, _abi: &abi::Abi, + unsafety: &ast::Unsafety, abi: &abi::Abi, gen: &ast::Generics) -> Function { debug!("Visiting fn"); Function { @@ -133,6 +136,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { whence: item.span, generics: gen.clone(), unsafety: *unsafety, + abi: *abi, } } @@ -171,7 +175,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { please_inline) }).collect::>(); - if mine.len() == 0 { + if mine.is_empty() { None } else { Some(ast::ViewPathList(p, mine)) @@ -209,6 +213,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let ret = match tcx.map.get(def.node) { ast_map::NodeItem(it) => { if glob { + let prev = mem::replace(&mut self.inlining_from_glob, true); match it.node { ast::ItemMod(ref m) => { for i in &m.items { @@ -218,6 +223,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { ast::ItemEnum(..) => {} _ => { panic!("glob not mapped to a module or enum"); } } + self.inlining_from_glob = prev; } else { self.visit_item(it, renamed, om); } @@ -356,7 +362,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { vis: item.vis, stab: self.stability(item.id), }; - om.impls.push(i); + // Don't duplicate impls when inlining glob imports, we'll pick + // them up regardless of where they're located. + if !self.inlining_from_glob { + om.impls.push(i); + } }, ast::ItemDefaultImpl(unsafety, ref trait_ref) => { let i = DefaultImpl { @@ -366,7 +376,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: item.attrs.clone(), whence: item.span, }; - om.def_traits.push(i); + // see comment above about ItemImpl + if !self.inlining_from_glob { + om.def_traits.push(i); + } } ast::ItemForeignMod(ref fm) => { om.foreigns.push(fm.clone()); diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 5890bdec8c..f57b852ea5 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -204,12 +204,10 @@ use std::io::prelude::*; use std::io; use std::mem::swap; use std::num::FpCategory as Fp; -#[allow(deprecated)] -use std::num::wrapping::WrappingOps; use std::ops::Index; use std::str::FromStr; use std::string; -use std::{char, f64, fmt, num, str}; +use std::{char, f64, fmt, str}; use std; use unicode::str as unicode_str; use unicode::str::Utf16Item; @@ -460,8 +458,8 @@ fn spaces(wr: &mut fmt::Write, mut n: usize) -> EncodeResult { fn fmt_number_or_null(v: f64) -> string::String { match v.classify() { Fp::Nan | Fp::Infinite => string::String::from_str("null"), - _ if v.fract() != 0f64 => f64::to_str_digits(v, 6), - _ => f64::to_str_digits(v, 6) + ".0", + _ if v.fract() != 0f64 => v.to_string(), + _ => v.to_string() + ".0", } } @@ -1165,7 +1163,7 @@ impl Json { pub fn as_i64(&self) -> Option { match *self { Json::I64(n) => Some(n), - Json::U64(n) => num::cast(n), + Json::U64(n) => Some(n as i64), _ => None } } @@ -1174,7 +1172,7 @@ impl Json { /// Returns None otherwise. pub fn as_u64(&self) -> Option { match *self { - Json::I64(n) => num::cast(n), + Json::I64(n) => Some(n as u64), Json::U64(n) => Some(n), _ => None } @@ -1184,8 +1182,8 @@ impl Json { /// Returns None otherwise. pub fn as_f64(&self) -> Option { match *self { - Json::I64(n) => num::cast(n), - Json::U64(n) => num::cast(n), + Json::I64(n) => Some(n as f64), + Json::U64(n) => Some(n as f64), Json::F64(n) => Some(n), _ => None } @@ -1540,7 +1538,7 @@ impl> Parser { F64Value(res) } else { if neg { - let res = -(res as i64); + let res = !(res as i64) + 1; // wrapping_neg // Make sure we didn't underflow. if res > 0 { @@ -1556,7 +1554,7 @@ impl> Parser { #[allow(deprecated)] // possible resolve bug is mapping these to traits fn parse_u64(&mut self) -> Result { - let mut accum = 0; + let mut accum = 0u64; let last_accum = 0; // necessary to detect overflow. match self.ch_or_null() { @@ -2121,14 +2119,8 @@ macro_rules! read_primitive { ($name:ident, $ty:ty) => { fn $name(&mut self) -> DecodeResult<$ty> { match self.pop() { - Json::I64(f) => match num::cast(f) { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_string(), format!("{}", f))), - }, - Json::U64(f) => match num::cast(f) { - Some(f) => Ok(f), - None => Err(ExpectedError("Number".to_string(), format!("{}", f))), - }, + Json::I64(f) => Ok(f as $ty), + Json::U64(f) => Ok(f as $ty), Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), // re: #12967.. a type w/ numeric keys (ie HashMap etc) // is going to have a string here, as per JSON spec. @@ -2627,9 +2619,9 @@ mod tests { use super::{Json, from_str, DecodeResult, DecoderError, JsonEvent, Parser, StackElement, Stack, Decoder, Encoder, EncoderError}; use std::{i64, u64, f32, f64}; + use std::io::prelude::*; use std::collections::BTreeMap; use std::string; - use std::old_io::Writer; #[derive(RustcDecodable, Eq, PartialEq, Debug)] struct OptionData { @@ -3464,7 +3456,6 @@ mod tests { #[test] fn test_encode_hashmap_with_numeric_key() { use std::str::from_utf8; - use std::old_io::Writer; use std::collections::HashMap; let mut hm: HashMap = HashMap::new(); hm.insert(1, true); @@ -3480,7 +3471,6 @@ mod tests { #[test] fn test_prettyencode_hashmap_with_numeric_key() { use std::str::from_utf8; - use std::old_io::Writer; use std::collections::HashMap; let mut hm: HashMap = HashMap::new(); hm.insert(1, true); @@ -3839,7 +3829,7 @@ mod tests { let mut stack = Stack::new(); assert!(stack.is_empty()); - assert!(stack.len() == 0); + assert!(stack.is_empty()); assert!(!stack.last_is_index()); stack.push_index(0); diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 2e86712c9b..dde79b123e 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -30,13 +30,12 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] #![feature(core)] -#![feature(old_path)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(std_misc)] #![feature(unicode)] #![feature(str_char)] -#![cfg_attr(test, feature(test, old_io))] +#![cfg_attr(test, feature(test))] // test harness access #[cfg(test)] extern crate test; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 81b5d4c581..af13873461 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -14,8 +14,6 @@ Core encoding and decoding interfaces. */ -#[allow(deprecated)] -use std::old_path::{self, GenericPath}; use std::path; use std::rc::Rc; use std::cell::{Cell, RefCell}; @@ -540,36 +538,6 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -#[allow(deprecated)] -impl Encodable for old_path::posix::Path { - fn encode(&self, e: &mut S) -> Result<(), S::Error> { - self.as_vec().encode(e) - } -} - -#[allow(deprecated)] -impl Decodable for old_path::posix::Path { - fn decode(d: &mut D) -> Result { - let bytes: Vec = try!(Decodable::decode(d)); - Ok(old_path::posix::Path::new(bytes)) - } -} - -#[allow(deprecated)] -impl Encodable for old_path::windows::Path { - fn encode(&self, e: &mut S) -> Result<(), S::Error> { - self.as_vec().encode(e) - } -} - -#[allow(deprecated)] -impl Decodable for old_path::windows::Path { - fn decode(d: &mut D) -> Result { - let bytes: Vec = try!(Decodable::decode(d)); - Ok(old_path::windows::Path::new(bytes)) - } -} - impl Encodable for path::PathBuf { fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.to_str().unwrap().encode(e) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 20ad71a4bf..a2ba8c4c1b 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -23,12 +23,12 @@ use mem; #[unstable(feature = "std_misc", reason = "would prefer to do this in a more general way")] pub trait OwnedAsciiExt { - /// Convert the string to ASCII upper case: + /// Converts the string to ASCII upper case: /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', /// but non-ASCII letters are unchanged. fn into_ascii_uppercase(self) -> Self; - /// Convert the string to ASCII lower case: + /// Converts the string to ASCII lower case: /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', /// but non-ASCII letters are unchanged. fn into_ascii_lowercase(self) -> Self; @@ -41,7 +41,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] type Owned; - /// Check if within the ASCII range. + /// Checks if within the ASCII range. /// /// # Examples /// @@ -95,7 +95,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn to_ascii_lowercase(&self) -> Self::Owned; - /// Check that two strings are an ASCII case-insensitive match. + /// Checks that two strings are an ASCII case-insensitive match. /// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporary strings. @@ -117,7 +117,7 @@ pub trait AsciiExt { #[stable(feature = "rust1", since = "1.0.0")] fn eq_ignore_ascii_case(&self, other: &Self) -> bool; - /// Convert this type to its ASCII upper case equivalent in-place. + /// Converts this type to its ASCII upper case equivalent in-place. /// /// See `to_ascii_uppercase` for more information. /// @@ -136,7 +136,7 @@ pub trait AsciiExt { #[unstable(feature = "ascii")] fn make_ascii_uppercase(&mut self); - /// Convert this type to its ASCII lower case equivalent in-place. + /// Converts this type to its ASCII lower case equivalent in-place. /// /// See `to_ascii_lowercase` for more information. /// diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a636c1a812..16b2c45bd8 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -506,7 +506,7 @@ impl HashMap } impl HashMap { - /// Create an empty HashMap. + /// Creates an empty HashMap. /// /// # Examples /// @@ -563,7 +563,7 @@ impl HashMap } } - /// Create an empty HashMap with space for at least `capacity` + /// Creates an empty HashMap with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -916,33 +916,6 @@ impl HashMap IterMut { inner: self.table.iter_mut() } } - /// Creates a consuming iterator, that is, one that moves each key-value - /// pair out of the map in arbitrary order. The map cannot be used after - /// calling this. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // Not possible with .iter() - /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - fn last_two((_, b, c): (A, B, C)) -> (B, C) { (b, c) } - let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; - - IntoIter { - inner: self.table.into_iter().map(last_two) - } - } - /// Gets the given key's corresponding entry in the map for in-place manipulation. #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry { @@ -1094,9 +1067,8 @@ impl HashMap /// /// let mut map = HashMap::new(); /// map.insert(1, "a"); - /// match map.get_mut(&1) { - /// Some(x) => *x = "b", - /// None => (), + /// if let Some(x) = map.get_mut(&1) { + /// *x = "b"; /// } /// assert_eq!(map[&1], "b"); /// ``` @@ -1107,7 +1079,7 @@ impl HashMap self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } - /// Inserts a key-value pair from the map. If the key already had a value + /// Inserts a key-value pair into the map. If the key already had a value /// present in the map, that value is returned. Otherwise, `None` is returned. /// /// # Examples @@ -1391,8 +1363,30 @@ impl IntoIterator for HashMap type Item = (K, V); type IntoIter = IntoIter; + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Not possible with .iter() + /// let vec: Vec<(&str, isize)> = map.into_iter().collect(); + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + fn last_two((_, b, c): (A, B, C)) -> (B, C) { (b, c) } + let last_two: fn((SafeHash, K, V)) -> (K, V) = last_two; + + IntoIter { + inner: self.table.into_iter().map(last_two) + } } } @@ -1469,7 +1463,6 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { } impl<'a, K, V> Entry<'a, K, V> { - /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant. #[unstable(feature = "std_misc", reason = "will soon be replaced by or_insert")] #[deprecated(since = "1.0", @@ -1596,7 +1589,7 @@ pub struct RandomState { #[unstable(feature = "std_misc", reason = "hashing an hash maps may be altered")] impl RandomState { - /// Construct a new `RandomState` that is initialized with random keys. + /// Constructs a new `RandomState` that is initialized with random keys. #[inline] #[allow(deprecated)] pub fn new() -> RandomState { @@ -1629,9 +1622,9 @@ mod test_map { use super::HashMap; use super::Entry::{Occupied, Vacant}; - use iter::{range_inclusive, range_step_inclusive, repeat}; + use iter::{range_inclusive, repeat}; use cell::RefCell; - use rand::{weak_rng, Rng}; + use rand::{thread_rng, Rng}; #[test] fn test_create_capacity_zero() { @@ -1865,7 +1858,7 @@ mod test_map { } // remove backwards - for i in range_step_inclusive(1000, 1, -1) { + for i in (1..1001).rev() { assert!(m.remove(&i).is_some()); for j in range_inclusive(i, 1000) { @@ -2290,7 +2283,7 @@ mod test_map { } let mut m = HashMap::new(); - let mut rng = weak_rng(); + let mut rng = thread_rng(); // Populate the map with some items. for _ in 0..50 { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 5fbc21797a..c51fceddd5 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -111,7 +111,7 @@ pub struct HashSet { } impl HashSet { - /// Create an empty HashSet. + /// Creates an empty HashSet. /// /// # Examples /// @@ -125,7 +125,7 @@ impl HashSet { HashSet::with_capacity(INITIAL_CAPACITY) } - /// Create an empty HashSet with space for at least `n` elements in + /// Creates an empty HashSet with space for at least `n` elements in /// the hash table. /// /// # Examples @@ -166,7 +166,7 @@ impl HashSet HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) } - /// Create an empty HashSet with space for at least `capacity` + /// Creates an empty HashSet with space for at least `capacity` /// elements in the hash table, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -271,40 +271,11 @@ impl HashSet Iter { iter: self.map.keys() } } - /// Creates a consuming iterator, that is, one that moves each value out - /// of the set in arbitrary order. The set cannot be used after calling - /// this. - /// - /// # Examples - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a".to_string()); - /// set.insert("b".to_string()); - /// - /// // Not possible to collect to a Vec with a regular `.iter()`. - /// let v: Vec = set.into_iter().collect(); - /// - /// // Will print in an arbitrary order. - /// for x in v.iter() { - /// println!("{}", x); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_iter(self) -> IntoIter { - fn first((a, _): (A, B)) -> A { a } - let first: fn((T, ())) -> T = first; - - IntoIter { iter: self.map.into_iter().map(first) } - } - /// Visit the values representing the difference. /// /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); @@ -335,7 +306,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); @@ -362,7 +332,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); @@ -388,7 +357,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); /// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); @@ -406,7 +374,7 @@ impl HashSet Union { iter: self.iter().chain(other.difference(self)) } } - /// Return the number of elements in the set + /// Returns the number of elements in the set. /// /// # Examples /// @@ -421,7 +389,7 @@ impl HashSet #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.map.len() } - /// Returns true if the set contains no elements + /// Returns true if the set contains no elements. /// /// # Examples /// @@ -434,7 +402,7 @@ impl HashSet /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { self.map.len() == 0 } + pub fn is_empty(&self) -> bool { self.map.is_empty() } /// Clears the set, returning all elements in an iterator. #[inline] @@ -471,7 +439,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// /// let set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); @@ -491,7 +458,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// /// let a: HashSet<_> = [1, 2, 3].iter().cloned().collect(); @@ -513,7 +479,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// /// let sup: HashSet<_> = [1, 2, 3].iter().cloned().collect(); @@ -535,7 +500,6 @@ impl HashSet /// # Examples /// /// ``` - /// # #![feature(core)] /// use std::collections::HashSet; /// /// let sub: HashSet<_> = [1, 2].iter().cloned().collect(); @@ -858,8 +822,31 @@ impl IntoIterator for HashSet type Item = T; type IntoIter = IntoIter; + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in v.iter() { + /// println!("{}", x); + /// } + /// ``` fn into_iter(self) -> IntoIter { - self.into_iter() + fn first((a, _): (A, B)) -> A { a } + let first: fn((T, ())) -> T = first; + + IntoIter { iter: self.map.into_iter().map(first) } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index dec6d1e220..3636457ea2 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -19,7 +19,7 @@ use iter::{Iterator, ExactSizeIterator}; use marker::{Copy, Send, Sync, Sized, self}; use mem::{min_align_of, size_of}; use mem; -use num::wrapping::{OverflowingOps, WrappingOps}; +use num::wrapping::OverflowingOps; use ops::{Deref, DerefMut, Drop}; use option::Option; use option::Option::{Some, None}; diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 0ac97b7129..48b95ce643 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -10,16 +10,18 @@ //! Collection types. //! -//! Rust's standard collection library provides efficient implementations of the most common -//! general purpose programming data structures. By using the standard implementations, -//! it should be possible for two libraries to communicate without significant data conversion. -//! -//! To get this out of the way: you should probably just use `Vec` or `HashMap`. These two -//! collections cover most use cases for generic data storage and processing. They are -//! exceptionally good at doing what they do. All the other collections in the standard -//! library have specific use cases where they are the optimal choice, but these cases are -//! borderline *niche* in comparison. Even when `Vec` and `HashMap` are technically suboptimal, -//! they're probably a good enough choice to get started. +//! Rust's standard collection library provides efficient implementations of the +//! most common general purpose programming data structures. By using the +//! standard implementations, it should be possible for two libraries to +//! communicate without significant data conversion. +//! +//! To get this out of the way: you should probably just use `Vec` or `HashMap`. +//! These two collections cover most use cases for generic data storage and +//! processing. They are exceptionally good at doing what they do. All the other +//! collections in the standard library have specific use cases where they are +//! the optimal choice, but these cases are borderline *niche* in comparison. +//! Even when `Vec` and `HashMap` are technically suboptimal, they're probably a +//! good enough choice to get started. //! //! Rust's collections can be grouped into four major categories: //! @@ -30,28 +32,31 @@ //! //! # When Should You Use Which Collection? //! -//! These are fairly high-level and quick break-downs of when each collection should be -//! considered. Detailed discussions of strengths and weaknesses of individual collections -//! can be found on their own documentation pages. +//! These are fairly high-level and quick break-downs of when each collection +//! should be considered. Detailed discussions of strengths and weaknesses of +//! individual collections can be found on their own documentation pages. //! //! ### Use a `Vec` when: -//! * You want to collect items up to be processed or sent elsewhere later, and don't care about -//! any properties of the actual values being stored. -//! * You want a sequence of elements in a particular order, and will only be appending to -//! (or near) the end. +//! * You want to collect items up to be processed or sent elsewhere later, and +//! don't care about any properties of the actual values being stored. +//! * You want a sequence of elements in a particular order, and will only be +//! appending to (or near) the end. //! * You want a stack. //! * You want a resizable array. //! * You want a heap-allocated array. //! //! ### Use a `VecDeque` when: -//! * You want a `Vec` that supports efficient insertion at both ends of the sequence. +//! * You want a `Vec` that supports efficient insertion at both ends of the +//! sequence. //! * You want a queue. //! * You want a double-ended queue (deque). //! //! ### Use a `LinkedList` when: -//! * You want a `Vec` or `VecDeque` of unknown size, and can't tolerate amortization. +//! * You want a `Vec` or `VecDeque` of unknown size, and can't tolerate +//! amortization. //! * You want to efficiently split and append lists. -//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked list. +//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked +//! list. //! //! ### Use a `HashMap` when: //! * You want to associate arbitrary keys with an arbitrary value. @@ -60,7 +65,8 @@ //! //! ### Use a `BTreeMap` when: //! * You're interested in what the smallest or largest key-value pair is. -//! * You want to find the largest or smallest key that is smaller or larger than something +//! * You want to find the largest or smallest key that is smaller or larger +//! than something //! * You want to be able to get all of the entries in order on-demand. //! * You want a sorted map. //! @@ -81,29 +87,34 @@ //! * You want a `BitVec`, but want `Set` properties //! //! ### Use a `BinaryHeap` when: -//! * You want to store a bunch of elements, but only ever want to process the "biggest" -//! or "most important" one at any given time. +//! +//! * You want to store a bunch of elements, but only ever want to process the +//! "biggest" or "most important" one at any given time. //! * You want a priority queue. //! //! # Performance //! -//! Choosing the right collection for the job requires an understanding of what each collection -//! is good at. Here we briefly summarize the performance of different collections for certain -//! important operations. For further details, see each type's documentation, and note that the -//! names of actual methods may differ from the tables below on certain collections. +//! Choosing the right collection for the job requires an understanding of what +//! each collection is good at. Here we briefly summarize the performance of +//! different collections for certain important operations. For further details, +//! see each type's documentation, and note that the names of actual methods may +//! differ from the tables below on certain collections. //! -//! Throughout the documentation, we will follow a few conventions. For all operations, -//! the collection's size is denoted by n. If another collection is involved in the operation, it -//! contains m elements. Operations which have an *amortized* cost are suffixed with a `*`. -//! Operations with an *expected* cost are suffixed with a `~`. +//! Throughout the documentation, we will follow a few conventions. For all +//! operations, the collection's size is denoted by n. If another collection is +//! involved in the operation, it contains m elements. Operations which have an +//! *amortized* cost are suffixed with a `*`. Operations with an *expected* +//! cost are suffixed with a `~`. //! -//! All amortized costs are for the potential need to resize when capacity is exhausted. -//! If a resize occurs it will take O(n) time. Our collections never automatically shrink, -//! so removal operations aren't amortized. Over a sufficiently large series of -//! operations, the average cost per operation will deterministically equal the given cost. +//! All amortized costs are for the potential need to resize when capacity is +//! exhausted. If a resize occurs it will take O(n) time. Our collections never +//! automatically shrink, so removal operations aren't amortized. Over a +//! sufficiently large series of operations, the average cost per operation will +//! deterministically equal the given cost. //! -//! Only HashMap has expected costs, due to the probabilistic nature of hashing. It is -//! theoretically possible, though very unlikely, for HashMap to experience worse performance. +//! Only HashMap has expected costs, due to the probabilistic nature of hashing. +//! It is theoretically possible, though very unlikely, for HashMap to +//! experience worse performance. //! //! ## Sequences //! @@ -120,7 +131,8 @@ //! //! ## Maps //! -//! For Sets, all operations have the cost of the equivalent Map operation. For BitSet, +//! For Sets, all operations have the cost of the equivalent Map operation. For +//! BitSet, //! refer to VecMap. //! //! | | get | insert | remove | predecessor | @@ -129,85 +141,95 @@ //! | BTreeMap | O(log n) | O(log n) | O(log n) | O(log n) | //! | VecMap | O(1) | O(1)? | O(1) | O(n) | //! -//! Note that VecMap is *incredibly* inefficient in terms of space. The O(1) insertion time -//! assumes space for the element is already allocated. Otherwise, a large key may require a -//! massive reallocation, with no direct relation to the number of elements in the collection. -//! VecMap should only be seriously considered for small keys. +//! Note that VecMap is *incredibly* inefficient in terms of space. The O(1) +//! insertion time assumes space for the element is already allocated. +//! Otherwise, a large key may require a massive reallocation, with no direct +//! relation to the number of elements in the collection. VecMap should only be +//! seriously considered for small keys. //! //! Note also that BTreeMap's precise preformance depends on the value of B. //! //! # Correct and Efficient Usage of Collections //! -//! Of course, knowing which collection is the right one for the job doesn't instantly -//! permit you to use it correctly. Here are some quick tips for efficient and correct -//! usage of the standard collections in general. If you're interested in how to use a -//! specific collection in particular, consult its documentation for detailed discussion -//! and code examples. +//! Of course, knowing which collection is the right one for the job doesn't +//! instantly permit you to use it correctly. Here are some quick tips for +//! efficient and correct usage of the standard collections in general. If +//! you're interested in how to use a specific collection in particular, consult +//! its documentation for detailed discussion and code examples. //! //! ## Capacity Management //! -//! Many collections provide several constructors and methods that refer to "capacity". -//! These collections are generally built on top of an array. Optimally, this array would be -//! exactly the right size to fit only the elements stored in the collection, but for the -//! collection to do this would be very inefficient. If the backing array was exactly the -//! right size at all times, then every time an element is inserted, the collection would -//! have to grow the array to fit it. Due to the way memory is allocated and managed on most -//! computers, this would almost surely require allocating an entirely new array and -//! copying every single element from the old one into the new one. Hopefully you can -//! see that this wouldn't be very efficient to do on every operation. -//! -//! Most collections therefore use an *amortized* allocation strategy. They generally let -//! themselves have a fair amount of unoccupied space so that they only have to grow -//! on occasion. When they do grow, they allocate a substantially larger array to move -//! the elements into so that it will take a while for another grow to be required. While -//! this strategy is great in general, it would be even better if the collection *never* -//! had to resize its backing array. Unfortunately, the collection itself doesn't have -//! enough information to do this itself. Therefore, it is up to us programmers to give it -//! hints. -//! -//! Any `with_capacity` constructor will instruct the collection to allocate enough space -//! for the specified number of elements. Ideally this will be for exactly that many -//! elements, but some implementation details may prevent this. `Vec` and `VecDeque` can -//! be relied on to allocate exactly the requested amount, though. Use `with_capacity` -//! when you know exactly how many elements will be inserted, or at least have a -//! reasonable upper-bound on that number. -//! -//! When anticipating a large influx of elements, the `reserve` family of methods can -//! be used to hint to the collection how much room it should make for the coming items. -//! As with `with_capacity`, the precise behavior of these methods will be specific to -//! the collection of interest. -//! -//! For optimal performance, collections will generally avoid shrinking themselves. -//! If you believe that a collection will not soon contain any more elements, or -//! just really need the memory, the `shrink_to_fit` method prompts the collection -//! to shrink the backing array to the minimum size capable of holding its elements. -//! -//! Finally, if ever you're interested in what the actual capacity of the collection is, -//! most collections provide a `capacity` method to query this information on demand. -//! This can be useful for debugging purposes, or for use with the `reserve` methods. +//! Many collections provide several constructors and methods that refer to +//! "capacity". These collections are generally built on top of an array. +//! Optimally, this array would be exactly the right size to fit only the +//! elements stored in the collection, but for the collection to do this would +//! be very inefficient. If the backing array was exactly the right size at all +//! times, then every time an element is inserted, the collection would have to +//! grow the array to fit it. Due to the way memory is allocated and managed on +//! most computers, this would almost surely require allocating an entirely new +//! array and copying every single element from the old one into the new one. +//! Hopefully you can see that this wouldn't be very efficient to do on every +//! operation. +//! +//! Most collections therefore use an *amortized* allocation strategy. They +//! generally let themselves have a fair amount of unoccupied space so that they +//! only have to grow on occasion. When they do grow, they allocate a +//! substantially larger array to move the elements into so that it will take a +//! while for another grow to be required. While this strategy is great in +//! general, it would be even better if the collection *never* had to resize its +//! backing array. Unfortunately, the collection itself doesn't have enough +//! information to do this itself. Therefore, it is up to us programmers to give +//! it hints. +//! +//! Any `with_capacity` constructor will instruct the collection to allocate +//! enough space for the specified number of elements. Ideally this will be for +//! exactly that many elements, but some implementation details may prevent +//! this. `Vec` and `VecDeque` can be relied on to allocate exactly the +//! requested amount, though. Use `with_capacity` when you know exactly how many +//! elements will be inserted, or at least have a reasonable upper-bound on that +//! number. +//! +//! When anticipating a large influx of elements, the `reserve` family of +//! methods can be used to hint to the collection how much room it should make +//! for the coming items. As with `with_capacity`, the precise behavior of +//! these methods will be specific to the collection of interest. +//! +//! For optimal performance, collections will generally avoid shrinking +//! themselves. If you believe that a collection will not soon contain any more +//! elements, or just really need the memory, the `shrink_to_fit` method prompts +//! the collection to shrink the backing array to the minimum size capable of +//! holding its elements. +//! +//! Finally, if ever you're interested in what the actual capacity of the +//! collection is, most collections provide a `capacity` method to query this +//! information on demand. This can be useful for debugging purposes, or for +//! use with the `reserve` methods. //! //! ## Iterators //! -//! Iterators are a powerful and robust mechanism used throughout Rust's standard -//! libraries. Iterators provide a sequence of values in a generic, safe, efficient -//! and convenient way. The contents of an iterator are usually *lazily* evaluated, -//! so that only the values that are actually needed are ever actually produced, and -//! no allocation need be done to temporarily store them. Iterators are primarily -//! consumed using a `for` loop, although many functions also take iterators where -//! a collection or sequence of values is desired. -//! -//! All of the standard collections provide several iterators for performing bulk -//! manipulation of their contents. The three primary iterators almost every collection -//! should provide are `iter`, `iter_mut`, and `into_iter`. Some of these are not -//! provided on collections where it would be unsound or unreasonable to provide them. +//! Iterators are a powerful and robust mechanism used throughout Rust's +//! standard libraries. Iterators provide a sequence of values in a generic, +//! safe, efficient and convenient way. The contents of an iterator are usually +//! *lazily* evaluated, so that only the values that are actually needed are +//! ever actually produced, and no allocation need be done to temporarily store +//! them. Iterators are primarily consumed using a `for` loop, although many +//! functions also take iterators where a collection or sequence of values is +//! desired. +//! +//! All of the standard collections provide several iterators for performing +//! bulk manipulation of their contents. The three primary iterators almost +//! every collection should provide are `iter`, `iter_mut`, and `into_iter`. +//! Some of these are not provided on collections where it would be unsound or +//! unreasonable to provide them. //! //! `iter` provides an iterator of immutable references to all the contents of a -//! collection in the most "natural" order. For sequence collections like `Vec`, this -//! means the items will be yielded in increasing order of index starting at 0. For ordered -//! collections like `BTreeMap`, this means that the items will be yielded in sorted order. -//! For unordered collections like `HashMap`, the items will be yielded in whatever order -//! the internal representation made most convenient. This is great for reading through -//! all the contents of the collection. +//! collection in the most "natural" order. For sequence collections like `Vec`, +//! this means the items will be yielded in increasing order of index starting +//! at 0. For ordered collections like `BTreeMap`, this means that the items +//! will be yielded in sorted order. For unordered collections like `HashMap`, +//! the items will be yielded in whatever order the internal representation made +//! most convenient. This is great for reading through all the contents of the +//! collection. //! //! ``` //! let vec = vec![1, 2, 3, 4]; @@ -216,8 +238,8 @@ //! } //! ``` //! -//! `iter_mut` provides an iterator of *mutable* references in the same order as `iter`. -//! This is great for mutating all the contents of the collection. +//! `iter_mut` provides an iterator of *mutable* references in the same order as +//! `iter`. This is great for mutating all the contents of the collection. //! //! ``` //! let mut vec = vec![1, 2, 3, 4]; @@ -226,13 +248,14 @@ //! } //! ``` //! -//! `into_iter` transforms the actual collection into an iterator over its contents -//! by-value. This is great when the collection itself is no longer needed, and the -//! values are needed elsewhere. Using `extend` with `into_iter` is the main way that -//! contents of one collection are moved into another. Calling `collect` on an iterator -//! itself is also a great way to convert one collection into another. Both of these -//! methods should internally use the capacity management tools discussed in the -//! previous section to do this as efficiently as possible. +//! `into_iter` transforms the actual collection into an iterator over its +//! contents by-value. This is great when the collection itself is no longer +//! needed, and the values are needed elsewhere. Using `extend` with `into_iter` +//! is the main way that contents of one collection are moved into another. +//! Calling `collect` on an iterator itself is also a great way to convert one +//! collection into another. Both of these methods should internally use the +//! capacity management tools discussed in the previous section to do this as +//! efficiently as possible. //! //! ``` //! let mut vec1 = vec![1, 2, 3, 4]; @@ -247,11 +270,12 @@ //! let buf: VecDeque<_> = vec.into_iter().collect(); //! ``` //! -//! Iterators also provide a series of *adapter* methods for performing common tasks to -//! sequences. Among the adapters are functional favorites like `map`, `fold`, `skip`, -//! and `take`. Of particular interest to collections is the `rev` adapter, that -//! reverses any iterator that supports this operation. Most collections provide reversible -//! iterators as the way to iterate over them in reverse order. +//! Iterators also provide a series of *adapter* methods for performing common +//! tasks to sequences. Among the adapters are functional favorites like `map`, +//! `fold`, `skip`, and `take`. Of particular interest to collections is the +//! `rev` adapter, that reverses any iterator that supports this operation. Most +//! collections provide reversible iterators as the way to iterate over them in +//! reverse order. //! //! ``` //! let vec = vec![1, 2, 3, 4]; @@ -260,48 +284,50 @@ //! } //! ``` //! -//! Several other collection methods also return iterators to yield a sequence of results -//! but avoid allocating an entire collection to store the result in. This provides maximum -//! flexibility as `collect` or `extend` can be called to "pipe" the sequence into any -//! collection if desired. Otherwise, the sequence can be looped over with a `for` loop. The -//! iterator can also be discarded after partial use, preventing the computation of the unused -//! items. +//! Several other collection methods also return iterators to yield a sequence +//! of results but avoid allocating an entire collection to store the result in. +//! This provides maximum flexibility as `collect` or `extend` can be called to +//! "pipe" the sequence into any collection if desired. Otherwise, the sequence +//! can be looped over with a `for` loop. The iterator can also be discarded +//! after partial use, preventing the computation of the unused items. //! //! ## Entries //! -//! The `entry` API is intended to provide an efficient mechanism for manipulating -//! the contents of a map conditionally on the presence of a key or not. The primary -//! motivating use case for this is to provide efficient accumulator maps. For instance, -//! if one wishes to maintain a count of the number of times each key has been seen, -//! they will have to perform some conditional logic on whether this is the first time -//! the key has been seen or not. Normally, this would require a `find` followed by an -//! `insert`, effectively duplicating the search effort on each insertion. -//! -//! When a user calls `map.entry(&key)`, the map will search for the key and then yield -//! a variant of the `Entry` enum. -//! -//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the -//! only valid operation is to `insert` a value into the entry. When this is done, -//! the vacant entry is consumed and converted into a mutable reference to the -//! the value that was inserted. This allows for further manipulation of the value -//! beyond the lifetime of the search itself. This is useful if complex logic needs to -//! be performed on the value regardless of whether the value was just inserted. -//! -//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, the user -//! has several options: they can `get`, `insert`, or `remove` the value of the occupied -//! entry. Additionally, they can convert the occupied entry into a mutable reference -//! to its value, providing symmetry to the vacant `insert` case. +//! The `entry` API is intended to provide an efficient mechanism for +//! manipulating the contents of a map conditionally on the presence of a key or +//! not. The primary motivating use case for this is to provide efficient +//! accumulator maps. For instance, if one wishes to maintain a count of the +//! number of times each key has been seen, they will have to perform some +//! conditional logic on whether this is the first time the key has been seen or +//! not. Normally, this would require a `find` followed by an `insert`, +//! effectively duplicating the search effort on each insertion. +//! +//! When a user calls `map.entry(&key)`, the map will search for the key and +//! then yield a variant of the `Entry` enum. +//! +//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case +//! the only valid operation is to `insert` a value into the entry. When this is +//! done, the vacant entry is consumed and converted into a mutable reference to +//! the the value that was inserted. This allows for further manipulation of the +//! value beyond the lifetime of the search itself. This is useful if complex +//! logic needs to be performed on the value regardless of whether the value was +//! just inserted. +//! +//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, +//! the user has several options: they can `get`, `insert`, or `remove` the +//! value of the occupied entry. Additionally, they can convert the occupied +//! entry into a mutable reference to its value, providing symmetry to the +//! vacant `insert` case. //! //! ### Examples //! -//! Here are the two primary ways in which `entry` is used. First, a simple example -//! where the logic performed on the values is trivial. +//! Here are the two primary ways in which `entry` is used. First, a simple +//! example where the logic performed on the values is trivial. //! //! #### Counting the number of times each character in a string occurs //! //! ``` -//! # #![feature(collections)] -//! use std::collections::btree_map::{BTreeMap, Entry}; +//! use std::collections::btree_map::BTreeMap; //! //! let mut count = BTreeMap::new(); //! let message = "she sells sea shells by the sea shore"; @@ -318,15 +344,14 @@ //! } //! ``` //! -//! When the logic to be performed on the value is more complex, we may simply use -//! the `entry` API to ensure that the value is initialized, and perform the logic -//! afterwards. +//! When the logic to be performed on the value is more complex, we may simply +//! use the `entry` API to ensure that the value is initialized, and perform the +//! logic afterwards. //! //! #### Tracking the inebriation of customers at a bar //! //! ``` -//! # #![feature(collections)] -//! use std::collections::btree_map::{BTreeMap, Entry}; +//! use std::collections::btree_map::BTreeMap; //! //! // A client of the bar. They have an id and a blood alcohol level. //! struct Person { id: u32, blood_alcohol: f32 } diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs index e76d5460eb..8ca462f5a3 100644 --- a/src/libstd/dynamic_lib.rs +++ b/src/libstd/dynamic_lib.rs @@ -105,7 +105,7 @@ impl DynamicLibrary { } } - /// Access the value at the symbol of the dynamic library + /// Accesses the value at the symbol of the dynamic library. pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { // This function should have a lifetime constraint of 'a on // T but that feature is still unimplemented @@ -259,19 +259,14 @@ mod dl { #[cfg(target_os = "windows")] mod dl { + use prelude::v1::*; + use ffi::OsStr; - use iter::Iterator; use libc; use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; - use ops::FnOnce; use sys::os; use os::windows::prelude::*; - use option::Option::{self, Some, None}; use ptr; - use result::Result; - use result::Result::{Ok, Err}; - use string::String; - use vec::Vec; use sys::c::compat::kernel32::SetThreadErrorMode; pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> { diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 931cf46a58..114d0dd79a 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -18,7 +18,6 @@ use prelude::v1::*; -use iter::IntoIterator; use error::Error; use ffi::{OsStr, OsString}; use fmt; @@ -261,7 +260,7 @@ pub fn set_var(k: &K, v: &V) os_imp::setenv(k.as_ref(), v.as_ref()) } -/// Remove an environment variable from the environment of the currently running process. +/// Removes an environment variable from the environment of the currently running process. /// /// # Examples /// @@ -772,7 +771,7 @@ mod tests { } fn eq(a: Option, b: Option<&str>) { - assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::from_str).map(|s| &*s)); + assert_eq!(a.as_ref().map(|s| &**s), b.map(OsStr::new).map(|s| &*s)); } #[test] @@ -895,7 +894,7 @@ mod tests { fn join_paths_unix() { fn test_eq(input: &[&str], output: &str) -> bool { &*join_paths(input.iter().cloned()).unwrap() == - OsStr::from_str(output) + OsStr::new(output) } assert!(test_eq(&[], "")); @@ -911,7 +910,7 @@ mod tests { fn join_paths_windows() { fn test_eq(input: &[&str], output: &str) -> bool { &*join_paths(input.iter().cloned()).unwrap() == - OsStr::from_str(output) + OsStr::new(output) } assert!(test_eq(&[], "")); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 150ffcdd77..9f09f464cf 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -50,7 +50,7 @@ use boxed::Box; use convert::From; use fmt::{self, Debug, Display}; -use marker::Send; +use marker::{Send, Sync}; use num; use option::Option; use option::Option::None; @@ -81,15 +81,15 @@ impl<'a, E: Error + 'a> From for Box { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + 'a> From for Box { - fn from(err: E) -> Box { +impl<'a, E: Error + Send + Sync + 'a> From for Box { + fn from(err: E) -> Box { Box::new(err) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { +impl From for Box { + fn from(err: String) -> Box { #[derive(Debug)] struct StringError(String); @@ -103,7 +103,14 @@ impl<'a, 'b> From<&'b str> for Box { } } - Box::new(StringError(String::from_str(err))) + Box::new(StringError(err)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + From::from(String::from_str(err)) } } @@ -115,10 +122,7 @@ impl Error for str::ParseBoolError { #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::Utf8Error { fn description(&self) -> &str { - match *self { - str::Utf8Error::TooShort => "invalid utf-8: not enough bytes", - str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", - } + "invalid utf-8: corrupt contents" } } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index de91e5f326..04513e9d04 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -18,8 +18,6 @@ use io; use iter::Iterator; use libc; use mem; -#[allow(deprecated)] -use old_io; use ops::Deref; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; @@ -133,7 +131,7 @@ pub struct CStr { pub struct NulError(usize, Vec); impl CString { - /// Create a new C-compatible string from a container of bytes. + /// Creates a new C-compatible string from a container of bytes. /// /// This method will consume the provided data and use the underlying bytes /// to construct a new string, ensuring that there is a trailing 0 byte. @@ -169,11 +167,12 @@ impl CString { } } - /// Create a C-compatible string from a byte vector without checking for + /// Creates a C-compatible string from a byte vector without checking for /// interior 0 bytes. /// - /// This method is equivalent to `from_vec` except that no runtime assertion - /// is made that `v` contains no 0 bytes. + /// This method is equivalent to `new` except that no runtime assertion + /// is made that `v` contains no 0 bytes, and it requires an actual + /// byte vector, not anything that can be converted to one with Into. #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { v.push(0); @@ -215,7 +214,7 @@ impl fmt::Debug for CString { impl NulError { /// Returns the position of the nul byte in the slice that was provided to - /// `CString::from_vec`. + /// `CString::new`. #[stable(feature = "rust1", since = "1.0.0")] pub fn nul_position(&self) -> usize { self.0 } @@ -245,20 +244,8 @@ impl From for io::Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl From for old_io::IoError { - fn from(_: NulError) -> old_io::IoError { - old_io::IoError { - kind: old_io::IoErrorKind::InvalidInput, - desc: "data provided contains a nul byte", - detail: None - } - } -} - impl CStr { - /// Cast a raw C string to a safe C string wrapper. + /// Casts a raw C string to a safe C string wrapper. /// /// This function will cast the provided `ptr` to the `CStr` wrapper which /// allows inspection and interoperation of non-owned C strings. This method @@ -301,7 +288,7 @@ impl CStr { mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) } - /// Return the inner pointer to this C string. + /// Returns the inner pointer to this C string. /// /// The returned pointer will be valid for as long as `self` is and points /// to a contiguous region of memory terminated with a 0 byte to represent @@ -311,7 +298,7 @@ impl CStr { self.inner.as_ptr() } - /// Convert this C string to a byte slice. + /// Converts this C string to a byte slice. /// /// This function will calculate the length of this string (which normally /// requires a linear amount of work to be done) and then return the @@ -329,7 +316,7 @@ impl CStr { &bytes[..bytes.len() - 1] } - /// Convert this C string to a byte slice containing the trailing 0 byte. + /// Converts this C string to a byte slice containing the trailing 0 byte. /// /// This function is the equivalent of `to_bytes` except that it will retain /// the trailing nul instead of chopping it off. diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 1b7e913d46..dfe706e077 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -20,11 +20,3 @@ pub use self::os_str::{OsString, OsStr}; mod c_str; mod os_str; - -// FIXME (#21670): these should be defined in the os_str module -/// Freely convertible to an `&OsStr` slice. -#[unstable(feature = "std_misc")] -pub trait AsOsStr { - /// Convert to an `&OsStr` slice. - fn as_os_str(&self) -> &OsStr; -} diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index ab20efe25e..97bf33335b 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -42,12 +42,10 @@ use string::String; use ops; use cmp; use hash::{Hash, Hasher}; -use old_path::{Path, GenericPath}; use vec::Vec; use sys::os_str::{Buf, Slice}; use sys_common::{AsInner, IntoInner, FromInner}; -use super::AsOsStr; /// Owned, mutable OS strings. #[derive(Clone)] @@ -69,7 +67,7 @@ impl OsString { OsString { inner: Buf::from_string(String::new()) } } - /// Construct an `OsString` from a byte sequence. + /// Constructs an `OsString` from a byte sequence. /// /// # Platform behavior /// @@ -94,13 +92,13 @@ impl OsString { from_bytes_inner(bytes.into()) } - /// Convert to an `OsStr` slice. + /// Converts to an `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { self } - /// Convert the `OsString` into a `String` if it contains valid Unicode data. + /// Converts the `OsString` into a `String` if it contains valid Unicode data. /// /// On failure, ownership of the original `OsString` is returned. #[stable(feature = "rust1", since = "1.0.0")] @@ -108,7 +106,7 @@ impl OsString { self.inner.into_string().map_err(|buf| OsString { inner: buf} ) } - /// Extend the string with the given `&OsStr` slice. + /// Extends the string with the given `&OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn push>(&mut self, s: T) { self.inner.push_slice(&s.as_ref().inner) @@ -221,21 +219,13 @@ impl Hash for OsString { } impl OsStr { - /// Coerce into an `OsStr` slice. + /// Coerces into an `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &OsStr { s.as_ref() } - /// Coerce directly from a `&str` slice to a `&OsStr` slice. - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", - reason = "use `OsStr::new` instead")] - pub fn from_str(s: &str) -> &OsStr { - unsafe { mem::transmute(Slice::from_str(s)) } - } - - /// Yield a `&str` slice if the `OsStr` is valid unicode. + /// Yields a `&str` slice if the `OsStr` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. #[stable(feature = "rust1", since = "1.0.0")] @@ -243,7 +233,7 @@ impl OsStr { self.inner.to_str() } - /// Convert an `OsStr` to a `Cow`. + /// Converts an `OsStr` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. #[stable(feature = "rust1", since = "1.0.0")] @@ -251,13 +241,13 @@ impl OsStr { self.inner.to_string_lossy() } - /// Copy the slice into an owned `OsString`. + /// Copies the slice into an owned `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_os_string(&self) -> OsString { OsString { inner: self.inner.to_owned() } } - /// Yield this `OsStr` as a byte slice. + /// Yields this `OsStr` as a byte slice. /// /// # Platform behavior /// @@ -275,7 +265,7 @@ impl OsStr { } } - /// Create a `CString` containing this `OsStr` data. + /// Creates a `CString` containing this `OsStr` data. /// /// Fails if the `OsStr` contains interior nulls. /// @@ -287,7 +277,7 @@ impl OsStr { self.to_bytes().and_then(|b| CString::new(b).ok()) } - /// Get the underlying byte representation. + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid /// revealing the internal, platform-specific encodings. @@ -379,46 +369,6 @@ impl ToOwned for OsStr { fn to_owned(&self) -> OsString { self.to_os_string() } } -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl<'a, T: AsOsStr + ?Sized> AsOsStr for &'a T { - fn as_os_str(&self) -> &OsStr { - (*self).as_os_str() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for OsStr { - fn as_os_str(&self) -> &OsStr { - self - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for OsString { - fn as_os_str(&self) -> &OsStr { - &self[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for str { - fn as_os_str(&self) -> &OsStr { - unsafe { mem::transmute(Slice::from_str(self)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for String { - fn as_os_str(&self) -> &OsStr { - unsafe { mem::transmute(Slice::from_str(self)) } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for OsStr { fn as_ref(&self) -> &OsStr { @@ -447,21 +397,6 @@ impl AsRef for String { } } -#[allow(deprecated)] -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for Path { - #[cfg(unix)] - fn as_os_str(&self) -> &OsStr { - unsafe { mem::transmute(self.as_vec()) } - } - #[cfg(windows)] - fn as_os_str(&self) -> &OsStr { - // currently .as_str() is actually infallible on windows - OsStr::from_str(self.as_str().unwrap()) - } -} - impl FromInner for OsString { fn from_inner(buf: Buf) -> OsString { OsString { inner: buf } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index eabc51beb1..d30d44a04d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -100,6 +100,38 @@ pub struct WalkDir { /// what operations are permitted on the open file. The `File::open` and /// `File::create` methods are aliases for commonly used options using this /// builder. +/// +/// Generally speaking, when using `OpenOptions`, you'll first call `new()`, +/// then chain calls to methods to set each option, then call `open()`, passing +/// the path of the file you're trying to open. This will give you a +/// [`io::Result`][result] with a [`File`][file] inside that you can further +/// operate on. +/// +/// [result]: ../io/type.Result.html +/// [file]: struct.File.html +/// +/// # Examples +/// +/// Opening a file to read: +/// +/// ```no_run +/// use std::fs::OpenOptions; +/// +/// let file = OpenOptions::new().read(true).open("foo.txt"); +/// ``` +/// +/// Opening a file for both reading and writing, as well as creating it if it +/// doesn't exist: +/// +/// ```no_run +/// use std::fs::OpenOptions; +/// +/// let file = OpenOptions::new() +/// .read(true) +/// .write(true) +/// .create(true) +/// .open("foo.txt"); +/// ``` #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OpenOptions(fs_imp::OpenOptions); @@ -139,7 +171,7 @@ impl File { OpenOptions::new().read(true).open(path) } - /// Open a file in write-only mode. + /// Opens a file in write-only mode. /// /// This function will create a file if it does not exist, /// and will truncate it if it does. @@ -169,7 +201,7 @@ impl File { self.path.as_ref().map(|p| &**p) } - /// Attempt to sync all OS-internal metadata to disk. + /// Attempts to sync all OS-internal metadata to disk. /// /// This function will attempt to ensure that all in-core data reaches the /// filesystem before returning. @@ -317,57 +349,105 @@ impl OpenOptions { /// Creates a blank net set of options ready for configuration. /// /// All options are initially set to `false`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> OpenOptions { OpenOptions(fs_imp::OpenOptions::new()) } - /// Set the option for read access. + /// Sets the option for read access. /// /// This option, when true, will indicate that the file should be /// `read`-able if opened. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().read(true).open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read(&mut self, read: bool) -> &mut OpenOptions { self.0.read(read); self } - /// Set the option for write access. + /// Sets the option for write access. /// /// This option, when true, will indicate that the file should be /// `write`-able if opened. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().write(true).open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn write(&mut self, write: bool) -> &mut OpenOptions { self.0.write(write); self } - /// Set the option for the append mode. + /// Sets the option for the append mode. /// /// This option, when true, means that writes will append to a file instead /// of overwriting previous contents. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().append(true).open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn append(&mut self, append: bool) -> &mut OpenOptions { self.0.append(append); self } - /// Set the option for truncating a previous file. + /// Sets the option for truncating a previous file. /// /// If a file is successfully opened with this option set it will truncate /// the file to 0 length if it already exists. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().truncate(true).open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions { self.0.truncate(truncate); self } - /// Set the option for creating a new file. + /// Sets the option for creating a new file. /// /// This option indicates whether a new file will be created if the file /// does not yet already exist. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().create(true).open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create(&mut self, create: bool) -> &mut OpenOptions { self.0.create(create); self } - /// Open a file at `path` with the options specified by `self`. + /// Opens a file at `path` with the options specified by `self`. /// /// # Errors /// @@ -378,6 +458,14 @@ impl OpenOptions { /// * Attempting to open a file with access that the user lacks /// permissions for /// * Filesystem-level errors (full disk, etc) + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// + /// let file = OpenOptions::new().open("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn open>(&self, path: P) -> io::Result { let path = path.as_ref(); @@ -392,18 +480,70 @@ impl AsInnerMut for OpenOptions { impl Metadata { /// Returns whether this metadata is for a directory. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// assert!(!metadata.is_dir()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_dir(&self) -> bool { self.0.is_dir() } /// Returns whether this metadata is for a regular file. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// assert!(metadata.is_file()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_file(&self) -> bool { self.0.is_file() } /// Returns the size of the file, in bytes, this metadata is for. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// assert_eq!(0, metadata.len()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> u64 { self.0.size() } /// Returns the permissions of the file this metadata is for. + /// + /// # Examples + /// + /// ``` + /// # fn foo() -> std::io::Result<()> { + /// use std::fs; + /// + /// let metadata = try!(fs::metadata("foo.txt")); + /// + /// assert!(!metadata.permissions().readonly()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn permissions(&self) -> Permissions { Permissions(self.0.perm()) @@ -430,13 +570,48 @@ impl Metadata { impl Permissions { /// Returns whether these permissions describe a readonly file. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// + /// assert_eq!(false, metadata.permissions().readonly()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn readonly(&self) -> bool { self.0.readonly() } - /// Modify the readonly flag for this set of permissions. + /// Modifies the readonly flag for this set of permissions. /// /// This operation does **not** modify the filesystem. To modify the /// filesystem use the `fs::set_permissions` function. + /// + /// # Examples + /// + /// ``` + /// use std::fs::File; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut f = try!(File::create("foo.txt")); + /// let metadata = try!(f.metadata()); + /// let mut permissions = metadata.permissions(); + /// + /// permissions.set_readonly(true); + /// + /// // filesystem doesn't change + /// assert_eq!(false, metadata.permissions().readonly()); + /// + /// // just this particular `permissions`. + /// assert_eq!(true, permissions.readonly()); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn set_readonly(&mut self, readonly: bool) { self.0.set_readonly(readonly) @@ -468,19 +643,34 @@ impl DirEntry { /// /// The full path is created by joining the original path to `read_dir` or /// `walk_dir` with the filename of this entry. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// # fn foo() -> std::io::Result<()> { + /// for entry in try!(fs::read_dir(".")) { + /// let dir = try!(entry); + /// println!("{:?}", dir.path()); + /// } + /// # Ok(()) + /// # } + /// ``` + /// + /// This prints output like: + /// + /// ```text + /// "./whatever.txt" + /// "./foo.html" + /// "./hello_world.rs" + /// ``` + /// + /// The exact text, of course, depends on what files you have in `.`. #[stable(feature = "rust1", since = "1.0.0")] pub fn path(&self) -> PathBuf { self.0.path() } } -/// Remove a file from the underlying filesystem. -/// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fs::remove_file("/some/file/path.txt"); -/// ``` +/// Removes a file from the underlying filesystem. /// /// Note that, just because an unlink call was successful, it is not /// guaranteed that a file is immediately deleted (e.g. depending on @@ -491,6 +681,17 @@ impl DirEntry { /// This function will return an error if `path` points to a directory, if the /// user lacks permissions to remove the file, or if some other filesystem-level /// error occurs. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::remove_file("a.txt")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file>(path: P) -> io::Result<()> { fs_imp::unlink(path.as_ref()) @@ -504,7 +705,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// /// # Examples /// -/// ```rust,no_run +/// ```rust /// # fn foo() -> std::io::Result<()> { /// use std::fs; /// @@ -526,20 +727,23 @@ pub fn metadata>(path: P) -> io::Result { /// Rename a file or directory to a new name. /// -/// # Examples -/// -/// ```rust,no_run -/// use std::fs; -/// -/// fs::rename("foo", "bar"); -/// ``` -/// /// # Errors /// /// This function will return an error if the provided `from` doesn't exist, if /// the process lacks permissions to view the contents, if `from` and `to` /// reside on separate filesystems, or if some other intermittent I/O error /// occurs. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::rename("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> { fs_imp::rename(from.as_ref(), to.as_ref()) @@ -553,14 +757,6 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// Note that if `from` and `to` both point to the same file, then the file /// will likely get truncated by this operation. /// -/// # Examples -/// -/// ``` -/// use std::fs; -/// -/// fs::copy("foo.txt", "bar.txt"); -/// ``` -/// /// # Errors /// /// This function will return an error in the following situations, but is not @@ -570,6 +766,16 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// * The `from` file does not exist /// * The current process does not have the permission rights to access /// `from` or write `to` +/// +/// # Examples +/// +/// ```no_run +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::copy("foo.txt", "bar.txt")); +/// # Ok(()) } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { let from = from.as_ref(); @@ -592,6 +798,17 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// /// The `dst` path will be a link pointing to the `src` path. Note that systems /// often require these two paths to both be located on the same filesystem. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::hard_link("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { fs_imp::link(src.as_ref(), dst.as_ref()) @@ -600,6 +817,17 @@ pub fn hard_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// Creates a new soft link on the filesystem. /// /// The `dst` path will be a soft link pointing to the `src` path. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::soft_link("a.txt", "b.txt")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<()> { fs_imp::symlink(src.as_ref(), dst.as_ref()) @@ -612,25 +840,39 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// This function will return an error on failure. Failure conditions include /// reading a file that does not exist or reading a file that is not a soft /// link. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn read_link>(path: P) -> io::Result { - fs_imp::readlink(path.as_ref()) -} - -/// Create a new, empty directory at the provided path /// /// # Examples /// /// ``` /// use std::fs; /// -/// fs::create_dir("/some/dir"); +/// # fn foo() -> std::io::Result<()> { +/// let path = try!(fs::read_link("a.txt")); +/// # Ok(()) +/// # } /// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn read_link>(path: P) -> io::Result { + fs_imp::readlink(path.as_ref()) +} + +/// Creates a new, empty directory at the provided path /// /// # Errors /// /// This function will return an error if the user lacks permissions to make a /// new directory at the provided `path`, or if the directory already exists. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::create_dir("/some/dir")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir>(path: P) -> io::Result<()> { fs_imp::mkdir(path.as_ref()) @@ -645,6 +887,17 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// does not already exist and it could not be created otherwise. The specific /// error conditions for when a directory is being created (after it is /// determined to not exist) are outlined by `fs::create_dir`. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::create_dir_all("/some/dir")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn create_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); @@ -653,20 +906,23 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { create_dir(path) } -/// Remove an existing, empty directory +/// Removes an existing, empty directory. +/// +/// # Errors +/// +/// This function will return an error if the user lacks permissions to remove +/// the directory at the provided `path`, or if the directory isn't empty. /// /// # Examples /// /// ``` /// use std::fs; /// -/// fs::remove_dir("/some/dir"); +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::remove_dir("/some/dir")); +/// # Ok(()) +/// # } /// ``` -/// -/// # Errors -/// -/// This function will return an error if the user lacks permissions to remove -/// the directory at the provided `path`, or if the directory isn't empty. #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir>(path: P) -> io::Result<()> { fs_imp::rmdir(path.as_ref()) @@ -680,7 +936,18 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// # Errors /// -/// See `file::remove_file` and `fs::remove_dir` +/// See `file::remove_file` and `fs::remove_dir`. +/// +/// # Examples +/// +/// ``` +/// use std::fs; +/// +/// # fn foo() -> std::io::Result<()> { +/// try!(fs::remove_dir_all("/some/dir")); +/// # Ok(()) +/// # } +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir_all>(path: P) -> io::Result<()> { let path = path.as_ref(); @@ -791,7 +1058,7 @@ impl Iterator for WalkDir { reason = "the precise set of methods exposed on this trait may \ change and some methods may be removed")] pub trait PathExt { - /// Get information on the file, directory, etc at this path. + /// Gets information on the file, directory, etc at this path. /// /// Consult the `fs::stat` documentation for more info. /// @@ -832,8 +1099,8 @@ impl PathExt for Path { /// Changes the timestamps for a file's last modification and access time. /// /// The file at the path specified will have its last access time set to -/// `atime` and its modification time set to `mtime`. The times specified should -/// be in milliseconds. +/// `accessed` and its modification time set to `modified`. The times specified +/// should be in milliseconds. #[unstable(feature = "fs_time", reason = "the argument type of u64 is not quite appropriate for \ this function and may change if the standard library \ @@ -928,7 +1195,8 @@ mod tests { pub fn tmpdir() -> TempDir { let p = env::temp_dir(); - let ret = p.join(&format!("rust-{}", rand::random::())); + let mut r = rand::thread_rng(); + let ret = p.join(&format!("rust-{}", r.next_u32())); check!(fs::create_dir(&ret)); TempDir(ret) } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 6fe35614a8..bd44a9547b 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -18,7 +18,7 @@ use io::prelude::*; use cmp; use error; use fmt; -use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind}; +use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; use ptr; use iter; @@ -120,6 +120,52 @@ impl fmt::Debug for BufReader where R: fmt::Debug { } } +#[unstable(feature = "buf_seek", reason = "recently added")] +impl Seek for BufReader { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with `SeekFrom::Current(_)` is the + /// position the underlying reader would be at if the `BufReader` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// `.unwrap()` immediately after a seek yields the underlying reader at + /// the same position. + /// + /// See `std::io::Seek` for more details. + /// + /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` + /// where `n` minus the internal buffer length underflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// `Err`, the underlying reader will be left at the same position it would + /// have if you seeked to `SeekFrom::Current(0)`. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 ebibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::min_value() so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = try!(self.inner.seek(SeekFrom::Current(offset))); + } else { + // seek backwards by our remainder, and then by the offset + try!(self.inner.seek(SeekFrom::Current(-remainder))); + self.pos = self.cap; // empty the buffer + result = try!(self.inner.seek(SeekFrom::Current(n))); + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = try!(self.inner.seek(pos)); + } + self.pos = self.cap; // empty the buffer + Ok(result) + } +} + /// Wraps a Writer and buffers output to it /// /// It can be excessively inefficient to work directly with a `Write`. For @@ -238,6 +284,16 @@ impl fmt::Debug for BufWriter where W: fmt::Debug { } } +#[unstable(feature = "buf_seek", reason = "recently added")] +impl Seek for BufWriter { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result { + self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + } +} + #[unsafe_destructor] impl Drop for BufWriter { fn drop(&mut self) { @@ -478,7 +534,7 @@ impl fmt::Debug for BufStream where S: fmt::Debug { mod tests { use prelude::v1::*; use io::prelude::*; - use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter}; + use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter, SeekFrom}; use test; /// A dummy reader intended at testing short-reads propagation. @@ -533,6 +589,67 @@ mod tests { assert_eq!(reader.read(&mut buf).unwrap(), 0); } + #[test] + fn test_buffered_reader_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); + assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); + reader.consume(1); + assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); + } + + #[test] + fn test_buffered_reader_seek_underflow() { + // gimmick reader that yields its position modulo 256 for each byte + struct PositionReader { + pos: u64 + } + impl Read for PositionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = buf.len(); + for x in buf { + *x = self.pos as u8; + self.pos = self.pos.wrapping_add(1); + } + Ok(len) + } + } + impl Seek for PositionReader { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(n) => { + self.pos = n; + } + SeekFrom::Current(n) => { + self.pos = self.pos.wrapping_add(n as u64); + } + SeekFrom::End(n) => { + self.pos = u64::max_value().wrapping_add(n as u64); + } + } + Ok(self.pos) + } + } + + let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // the following seek will require two underlying seeks + let expected = 9223372036854775802; + assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // seeking to 0 should empty the buffer. + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); + assert_eq!(reader.get_ref().pos, expected); + } + #[test] fn test_buffered_writer() { let inner = Vec::new(); @@ -576,6 +693,18 @@ mod tests { assert_eq!(w, [0, 1]); } + #[test] + fn test_buffered_writer_seek() { + let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); + w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); + w.write_all(&[6, 7]).unwrap(); + assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); + assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); + w.write_all(&[8, 9]).unwrap(); + assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); + } + // This is just here to make sure that we don't infinite loop in the // newtype struct autoderef weirdness #[test] diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 6433c29bb9..72743106ab 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -34,21 +34,21 @@ pub struct Cursor { } impl Cursor { - /// Create a new cursor wrapping the provided underlying I/O object. + /// Creates a new cursor wrapping the provided underlying I/O object. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: T) -> Cursor { Cursor { pos: 0, inner: inner } } - /// Consume this cursor, returning the underlying value. + /// Consumes this cursor, returning the underlying value. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> T { self.inner } - /// Get a reference to the underlying value in this cursor. + /// Gets a reference to the underlying value in this cursor. #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &T { &self.inner } - /// Get a mutable reference to the underlying value in this cursor. + /// Gets a mutable reference to the underlying value in this cursor. /// /// Care should be taken to avoid modifying the internal I/O state of the /// underlying value as it may corrupt this cursor's position. diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index b84dcb8fb6..97c5a29d30 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -12,7 +12,7 @@ use boxed::Box; use convert::Into; use error; use fmt; -use marker::Send; +use marker::{Send, Sync}; use option::Option::{self, Some, None}; use result; use sys; @@ -46,7 +46,7 @@ enum Repr { #[derive(Debug)] struct Custom { kind: ErrorKind, - error: Box, + error: Box, } /// A list specifying general categories of I/O error. @@ -146,7 +146,7 @@ impl Error { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into> + where E: Into> { Error { repr: Repr::Custom(Box::new(Custom { @@ -163,13 +163,12 @@ impl Error { /// `Error` for the error code. #[stable(feature = "rust1", since = "1.0.0")] pub fn last_os_error() -> Error { - Error::from_os_error(sys::os::errno() as i32) + Error::from_raw_os_error(sys::os::errno() as i32) } /// Creates a new instance of an `Error` from a particular OS error code. - #[unstable(feature = "io", - reason = "unclear whether this function is necessary")] - pub fn from_os_error(code: i32) -> Error { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_raw_os_error(code: i32) -> Error { Error { repr: Repr::Os(code) } } @@ -185,7 +184,7 @@ impl Error { } } - /// Return the corresponding `ErrorKind` for this error. + /// Returns the corresponding `ErrorKind` for this error. #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { match self.repr { @@ -217,3 +216,8 @@ impl error::Error for Error { } } } + +fn _assert_error_is_sync_send() { + fn _is_sync_send() {} + _is_sync_send::(); +} diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c6335015d7..07b43b6c5d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -148,7 +148,7 @@ pub trait Read { /// /// If the return value of this method is `Ok(n)`, then it must be /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates - /// that the buffer `buf` has ben filled in with `n` bytes of data from this + /// that the buffer `buf` has been filled in with `n` bytes of data from this /// source. If `n` is `0`, then it can indicate one of two scenarios: /// /// 1. This reader has reached its "end of file" and will likely no longer @@ -172,14 +172,11 @@ pub trait Read { /// Read all bytes until EOF in this source, placing them into `buf`. /// /// All bytes read from this source will be appended to the specified buffer - /// `buf`. This function will return a call to `read` either: + /// `buf`. This function will continuously call `read` to append more data to + /// `buf` until `read` returns either `Ok(0)` or an error of + /// non-`ErrorKind::Interrupted` kind. /// - /// 1. Returns `Ok(0)`. - /// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`. - /// - /// Until one of these conditions is met the function will continuously - /// invoke `read` to append more data to `buf`. If successful, this function - /// will return the total number of bytes read. + /// If successful, this function will return the total number of bytes read. /// /// # Errors /// @@ -220,14 +217,14 @@ pub trait Read { append_to_string(buf, |b| read_to_end(self, b)) } - /// Create a "by reference" adaptor for this instance of `Read`. + /// Creates a "by reference" adaptor for this instance of `Read`. /// /// The returned adaptor also implements `Read` and will simply borrow this /// current reader. #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } - /// Transform this `Read` instance to an `Iterator` over its bytes. + /// Transforms this `Read` instance to an `Iterator` over its bytes. /// /// The returned type implements `Iterator` where the `Item` is `Result`. The yielded item is `Ok` if a byte was successfully read and @@ -238,7 +235,7 @@ pub trait Read { Bytes { inner: self } } - /// Transform this `Read` instance to an `Iterator` over `char`s. + /// Transforms this `Read` instance to an `Iterator` over `char`s. /// /// This adaptor will attempt to interpret this reader as an UTF-8 encoded /// sequence of characters. The returned iterator will return `None` once @@ -255,7 +252,7 @@ pub trait Read { Chars { inner: self } } - /// Create an adaptor which will chain this stream with another. + /// Creates an adaptor which will chain this stream with another. /// /// The returned `Read` instance will first read all bytes from this object /// until EOF is encountered. Afterwards the output is equivalent to the @@ -265,7 +262,7 @@ pub trait Read { Chain { first: self, second: next, done_first: false } } - /// Create an adaptor which will read at most `limit` bytes from it. + /// Creates an adaptor which will read at most `limit` bytes from it. /// /// This function returns a new instance of `Read` which will read at most /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any @@ -352,7 +349,7 @@ pub trait Write { /// This function will return the first error that `write` returns. #[stable(feature = "rust1", since = "1.0.0")] fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while buf.len() > 0 { + while !buf.is_empty() { match self.write(buf) { Ok(0) => return Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")), @@ -406,7 +403,7 @@ pub trait Write { } } - /// Create a "by reference" adaptor for this instance of `Write`. + /// Creates a "by reference" adaptor for this instance of `Write`. /// /// The returned adaptor also implements `Write` and will simply borrow this /// current writer. @@ -618,9 +615,6 @@ pub trait BufRead: Read { /// The iterator returned from this function will yield instances of /// `io::Result`. Each string returned will *not* have a newline /// byte (the 0xA byte) at the end. - /// - /// This function will yield errors whenever `read_string` would have also - /// yielded an error. #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines where Self: Sized { Lines { buf: self } diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs index 333ae8f26a..880770eb41 100644 --- a/src/libstd/io/prelude.rs +++ b/src/libstd/io/prelude.rs @@ -14,6 +14,7 @@ //! by adding a glob import to the top of I/O heavy modules: //! //! ``` +//! # #![allow(unused_imports)] //! use std::io::prelude::*; //! ``` //! diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d361f17cbe..cd6af77daa 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ use io::lazy::Lazy; use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; +use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; /// Stdout used by print! and println! macros thread_local! { @@ -44,7 +45,7 @@ struct StdoutRaw(stdio::Stdout); /// the `std::io::stdio::stderr_raw` function. struct StderrRaw(stdio::Stderr); -/// Construct a new raw handle to the standard input of this process. +/// Constructs a new raw handle to the standard input of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdin`. Data buffered by the `std::io::stdin` @@ -53,7 +54,7 @@ struct StderrRaw(stdio::Stderr); /// The returned handle has no external synchronization or buffering. fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } -/// Construct a new raw handle to the standard input stream of this process. +/// Constructs a new raw handle to the standard input stream of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdout`. Note that data is buffered by the @@ -64,7 +65,7 @@ fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } /// top. fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) } -/// Construct a new raw handle to the standard input stream of this process. +/// Constructs a new raw handle to the standard input stream of this process. /// /// The returned handle does not interact with any other handles created nor /// handles returned by `std::io::stdout`. @@ -108,7 +109,7 @@ pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader>, } -/// Create a new handle to the global standard input stream of this process. +/// Creates a new handle to the global standard input stream of this process. /// /// The handle returned refers to a globally shared buffer between all threads. /// Access is synchronized and can be explicitly controlled with the `lock()` @@ -138,7 +139,7 @@ pub fn stdin() -> Stdin { } impl Stdin { - /// Lock this handle to the standard input stream, returning a readable + /// Locks this handle to the standard input stream, returning a readable /// guard. /// /// The lock is released when the returned lock goes out of scope. The @@ -210,7 +211,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>, + inner: Arc>>>, } /// A locked reference to the a `Stdout` handle. @@ -219,7 +220,7 @@ pub struct Stdout { /// method on `Stdout`. #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: MutexGuard<'a, LineWriter>, + inner: ReentrantMutexGuard<'a, RefCell>>, } /// Constructs a new reference to the standard output of the current process. @@ -231,18 +232,18 @@ pub struct StdoutLock<'a> { /// The returned handle implements the `Write` trait. #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>> = lazy_init!(stdout_init); + static INSTANCE: Lazy>>> = lazy_init!(stdout_init); return Stdout { inner: INSTANCE.get().expect("cannot access stdout during shutdown"), }; - fn stdout_init() -> Arc>> { - Arc::new(Mutex::new(LineWriter::new(stdout_raw()))) + fn stdout_init() -> Arc>>> { + Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))) } } impl Stdout { - /// Lock this handle to the standard output stream, returning a writable + /// Locks this handle to the standard output stream, returning a writable /// guard. /// /// The lock is released when the returned lock goes out of scope. The @@ -264,15 +265,18 @@ impl Write for Stdout { fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - // Don't override write_fmt as it's possible to run arbitrary code during a - // write_fmt, allowing the possibility of a recursive lock (aka deadlock) + fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + self.lock().write_fmt(args) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StdoutLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.borrow_mut().flush() } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } /// A handle to the standard error stream of a process. @@ -280,7 +284,7 @@ impl<'a> Write for StdoutLock<'a> { /// For more information, see `stderr` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: Arc>, + inner: Arc>>, } /// A locked reference to the a `Stderr` handle. @@ -289,7 +293,7 @@ pub struct Stderr { /// method on `Stderr`. #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: MutexGuard<'a, StderrRaw>, + inner: ReentrantMutexGuard<'a, RefCell>, } /// Constructs a new reference to the standard error stream of a process. @@ -300,18 +304,18 @@ pub struct StderrLock<'a> { /// The returned handle implements the `Write` trait. #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { - static INSTANCE: Lazy> = lazy_init!(stderr_init); + static INSTANCE: Lazy>> = lazy_init!(stderr_init); return Stderr { inner: INSTANCE.get().expect("cannot access stderr during shutdown"), }; - fn stderr_init() -> Arc> { - Arc::new(Mutex::new(stderr_raw())) + fn stderr_init() -> Arc>> { + Arc::new(ReentrantMutex::new(RefCell::new(stderr_raw()))) } } impl Stderr { - /// Lock this handle to the standard error stream, returning a writable + /// Locks this handle to the standard error stream, returning a writable /// guard. /// /// The lock is released when the returned lock goes out of scope. The @@ -333,14 +337,18 @@ impl Write for Stderr { fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.lock().write_all(buf) } - // Don't override write_fmt for the same reasons as Stdout + fn write_fmt(&mut self, args: fmt::Arguments) -> io::Result<()> { + self.lock().write_fmt(args) + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StderrLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { - self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + self.inner.borrow_mut().write(&buf[..cmp::min(buf.len(), OUT_MAX)]) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.borrow_mut().flush() } - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } /// Resets the task-local stderr handle to the specified writer diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 5c9ff544fa..7821ebede0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -77,9 +77,8 @@ //! including [`atomic`](sync/atomic/index.html), and [`mpsc`](sync/mpsc/index.html), //! which contains the channel types for message passing. //! -//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets, -//! timers, and process spawning, are defined in the -//! [`old_io`](old_io/index.html) module. +//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets, and +//! process spawning, are defined in the [`io`](io/index.html) module. //! //! Rust's I/O and concurrency depends on a small runtime interface //! that lives, along with its support code, in mod [`rt`](rt/index.html). @@ -104,7 +103,8 @@ html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/", html_playground_url = "http://play.rust-lang.org/")] -#![doc(test(no_crate_inject))] +#![doc(test(no_crate_inject, attr(deny(warnings))))] +#![doc(test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] #![feature(alloc)] #![feature(box_syntax)] @@ -128,6 +128,8 @@ #![feature(std_misc)] #![feature(slice_patterns)] #![feature(debug_builders)] +#![feature(zero_one)] +#![cfg_attr(test, feature(float_from_str_radix))] #![cfg_attr(test, feature(test, rustc_private, std_misc))] // Don't link to std. We are std. @@ -262,12 +264,9 @@ pub mod ffi; pub mod fs; pub mod io; pub mod net; -pub mod old_io; -pub mod old_path; pub mod os; pub mod path; pub mod process; -pub mod rand; pub mod sync; pub mod time; @@ -281,6 +280,18 @@ pub mod time; pub mod rt; mod panicking; +mod rand; + +// Some external utilities of the standard library rely on randomness (aka +// rustc_back::TempDir and tests) and need a way to get at the OS rng we've got +// here. This module is not at all intended for stabilization as-is, however, +// but it may be stabilized long-term. As a result we're exposing a hidden, +// unstable module so we can get our build working. +#[doc(hidden)] +#[unstable(feature = "rand")] +pub mod __rand { + pub use rand::{thread_rng, ThreadRng, Rng}; +} // Modules that exist purely to document + host impl docs for primitive types @@ -297,8 +308,6 @@ mod std { pub use sync; // used for select!() pub use error; // used for try!() pub use fmt; // used for any formatting strings - #[allow(deprecated)] - pub use old_io; // used for println!() pub use option; // used for bitflags!{} pub use rt; // used for panic!() pub use vec; // used for vec![] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index b3d1adb442..f3e99a8541 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -37,6 +37,8 @@ /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] +#[cfg(stage0)] macro_rules! panic { () => ({ panic!("explicit panic") @@ -54,7 +56,53 @@ macro_rules! panic { // used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. - static _FILE_LINE: (&'static str, usize) = (file!(), line!() as usize); + static _FILE_LINE: (&'static str, u32) = (file!(), line!()); + &_FILE_LINE + }) + }); +} + +/// The entry point for panic of Rust tasks. +/// +/// This macro is used to inject panic into a Rust task, causing the task to +/// unwind and panic entirely. Each task's panic can be reaped as the +/// `Box` type, and the single-argument form of the `panic!` macro will be +/// the value which is transmitted. +/// +/// The multi-argument form of this macro panics with a string and has the +/// `format!` syntax for building a string. +/// +/// # Examples +/// +/// ```should_panic +/// # #![allow(unreachable_code)] +/// panic!(); +/// panic!("this is a terrible mistake!"); +/// panic!(4); // panic with the value of 4 to be collected elsewhere +/// panic!("this is a {} {message}", "fancy", message = "message"); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] +#[cfg(not(stage0))] +macro_rules! panic { + () => ({ + panic!("explicit panic") + }); + ($msg:expr) => ({ + $crate::rt::begin_unwind($msg, { + // static requires less code at runtime, more constant data + static _FILE_LINE: (&'static str, u32) = (file!(), line!()); + &_FILE_LINE + }) + }); + ($fmt:expr, $($arg:tt)+) => ({ + $crate::rt::begin_unwind_fmt(format_args!($fmt, $($arg)+), { + // The leading _'s are to avoid dead code warnings if this is + // used inside a dead function. Just `#[allow(dead_code)]` is + // insufficient, since the user may have + // `#[forbid(dead_code)]` and which cannot be overridden. + static _FILE_LINE: (&'static str, u32) = (file!(), line!()); &_FILE_LINE }) }); diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 886f252fb1..2e34e46726 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -281,7 +281,6 @@ impl hash::Hash for SocketAddrV6 { /// Some examples: /// /// ```no_run -/// # #![feature(net)] /// use std::net::{SocketAddrV4, TcpStream, UdpSocket, TcpListener, Ipv4Addr}; /// /// fn main() { @@ -302,7 +301,7 @@ impl hash::Hash for SocketAddrV6 { /// let tcp_l = TcpListener::bind("localhost:12345"); /// /// let mut udp_s = UdpSocket::bind(("127.0.0.1", port)).unwrap(); -/// udp_s.send_to(&[7], (ip, 23451)); +/// udp_s.send_to(&[7], (ip, 23451)).unwrap(); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -462,261 +461,7 @@ mod tests { use io; use net::*; use net::Ipv6MulticastScope::*; - - #[test] - fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - "2a02:6b8::11:11".parse()); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), - "::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - "::FFFF:192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse()); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), - "77.88.21.11:80".parse()); - assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse()); - assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), - "[::127.0.0.1]:22".parse()); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), - "8:9:a:b:c:d:e:f"); - - // reduce a single run of zeros - assert_eq!("ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", - Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - } - - #[test] - fn ipv4_to_ipv6() { - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()); - } - - #[test] - fn ipv6_to_ipv4() { - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - None); - } - - #[test] - fn ipv4_properties() { - fn check(octets: &[u8; 4], unspec: bool, loopback: bool, - private: bool, link_local: bool, global: bool, - multicast: bool) { - let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); - assert_eq!(octets, &ip.octets()); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_private(), private); - assert_eq!(ip.is_link_local(), link_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_multicast(), multicast); - } - - // address unspec loopbk privt linloc global multicast - check(&[0, 0, 0, 0], true, false, false, false, true, false); - check(&[0, 0, 0, 1], false, false, false, false, true, false); - check(&[1, 0, 0, 0], false, false, false, false, true, false); - check(&[10, 9, 8, 7], false, false, true, false, false, false); - check(&[127, 1, 2, 3], false, true, false, false, false, false); - check(&[172, 31, 254, 253], false, false, true, false, false, false); - check(&[169, 254, 253, 242], false, false, false, true, false, false); - check(&[192, 168, 254, 253], false, false, true, false, false, false); - check(&[224, 0, 0, 0], false, false, false, false, true, true); - check(&[239, 255, 255, 255], false, false, false, false, true, true); - check(&[255, 255, 255, 255], false, false, false, false, true, false); - } - - #[test] - fn ipv6_properties() { - fn check(str_addr: &str, unspec: bool, loopback: bool, - unique_local: bool, global: bool, - u_link_local: bool, u_site_local: bool, u_global: bool, - m_scope: Option) { - let ip: Ipv6Addr = str_addr.parse().unwrap(); - assert_eq!(str_addr, ip.to_string()); - - assert_eq!(ip.is_unspecified(), unspec); - assert_eq!(ip.is_loopback(), loopback); - assert_eq!(ip.is_unique_local(), unique_local); - assert_eq!(ip.is_global(), global); - assert_eq!(ip.is_unicast_link_local(), u_link_local); - assert_eq!(ip.is_unicast_site_local(), u_site_local); - assert_eq!(ip.is_unicast_global(), u_global); - assert_eq!(ip.multicast_scope(), m_scope); - assert_eq!(ip.is_multicast(), m_scope.is_some()); - } - - // unspec loopbk uniqlo global unill unisl uniglo mscope - check("::", - true, false, false, true, false, false, true, None); - check("::1", - false, true, false, false, false, false, false, None); - check("::0.0.0.2", - false, false, false, true, false, false, true, None); - check("1::", - false, false, false, true, false, false, true, None); - check("fc00::", - false, false, true, false, false, false, false, None); - check("fdff:ffff::", - false, false, true, false, false, false, false, None); - check("fe80:ffff::", - false, false, false, false, true, false, false, None); - check("febf:ffff::", - false, false, false, false, true, false, false, None); - check("fec0::", - false, false, false, false, false, true, false, None); - check("ff01::", - false, false, false, false, false, false, false, Some(InterfaceLocal)); - check("ff02::", - false, false, false, false, false, false, false, Some(LinkLocal)); - check("ff03::", - false, false, false, false, false, false, false, Some(RealmLocal)); - check("ff04::", - false, false, false, false, false, false, false, Some(AdminLocal)); - check("ff05::", - false, false, false, false, false, false, false, Some(SiteLocal)); - check("ff08::", - false, false, false, false, false, false, false, Some(OrganizationLocal)); - check("ff0e::", - false, false, false, true, false, false, false, Some(Global)); - } - - fn tsa(a: A) -> Result, String> { - match a.to_socket_addrs() { - Ok(a) => Ok(a.collect()), - Err(e) => Err(e.to_string()), - } - } - - #[test] - fn to_socket_addr_socketaddr() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); - assert_eq!(Ok(vec![a]), tsa(a)); - } - - fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { - SocketAddr::V4(SocketAddrV4::new(a, p)) - } - - fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { - SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) - } + use net::test::{tsa, sa6, sa4}; #[test] fn to_socket_addr_ipaddr_u16() { @@ -750,8 +495,9 @@ mod tests { assert!(tsa("localhost:23924").unwrap().contains(&a)); } + // FIXME: figure out why this fails on bitrig and fix it #[test] - #[cfg(not(windows))] + #[cfg(not(any(windows, target_os = "bitrig")))] fn to_socket_addr_str_bad() { assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); } diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c8b1928747..065126c6fd 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -58,7 +58,7 @@ pub enum Ipv6MulticastScope { } impl Ipv4Addr { - /// Create a new IPv4 address from four eight-bit octets. + /// Creates a new IPv4 address from four eight-bit octets. /// /// The result will represent the IP address a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -115,9 +115,11 @@ impl Ipv4Addr { /// /// Non-globally-routable networks include the private networks (10.0.0.0/8, /// 172.16.0.0/12 and 192.168.0.0/16), the loopback network (127.0.0.0/8), - /// and the link-local network (169.254.0.0/16). + /// the link-local network (169.254.0.0/16), the broadcast address (255.255.255.255/32) and + /// the test networks used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) pub fn is_global(&self) -> bool { - !self.is_private() && !self.is_loopback() && !self.is_link_local() + !self.is_private() && !self.is_loopback() && !self.is_link_local() && + !self.is_broadcast() && !self.is_documentation() } /// Returns true if this is a multicast address. @@ -127,7 +129,30 @@ impl Ipv4Addr { self.octets()[0] >= 224 && self.octets()[0] <= 239 } - /// Convert this address to an IPv4-compatible IPv6 address + /// Returns true if this is a broadcast address. + /// + /// A broadcast address has all octets set to 255 as defined in RFC 919 + pub fn is_broadcast(&self) -> bool { + self.octets()[0] == 255 && self.octets()[1] == 255 && + self.octets()[2] == 255 && self.octets()[3] == 255 + } + + /// Returns true if this address is in a range designated for documentation + /// + /// This is defined in RFC 5737 + /// - 192.0.2.0/24 (TEST-NET-1) + /// - 198.51.100.0/24 (TEST-NET-2) + /// - 203.0.113.0/24 (TEST-NET-3) + pub fn is_documentation(&self) -> bool { + match(self.octets()[0], self.octets()[1], self.octets()[2], self.octets()[3]) { + (192, _, 2, _) => true, + (198, 51, 100, _) => true, + (203, _, 113, _) => true, + _ => false + } + } + + /// Converts this address to an IPv4-compatible IPv6 address /// /// a.b.c.d becomes ::a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -137,7 +162,7 @@ impl Ipv4Addr { ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16) } - /// Convert this address to an IPv4-mapped IPv6 address + /// Converts this address to an IPv4-mapped IPv6 address /// /// a.b.c.d becomes ::ffff:a.b.c.d #[stable(feature = "rust1", since = "1.0.0")] @@ -220,7 +245,7 @@ impl FromInner for Ipv4Addr { } impl Ipv6Addr { - /// Create a new IPv6 address from eight 16-bit segments. + /// Creates a new IPv6 address from eight 16-bit segments. /// /// The result will represent the IP address a:b:c:d:e:f:g:h #[stable(feature = "rust1", since = "1.0.0")] @@ -234,7 +259,7 @@ impl Ipv6Addr { } } - /// Return the eight 16-bit segments that make up this address + /// Returns the eight 16-bit segments that make up this address #[stable(feature = "rust1", since = "1.0.0")] pub fn segments(&self) -> [u16; 8] { [ntoh(self.inner.s6_addr[0]), @@ -324,7 +349,7 @@ impl Ipv6Addr { (self.segments()[0] & 0xff00) == 0xff00 } - /// Convert this address to an IPv4 address. Returns None if this address is + /// Converts this address to an IPv4 address. Returns None if this address is /// neither IPv4-compatible or IPv4-mapped. /// /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d @@ -461,3 +486,256 @@ impl FromInner for Ipv6Addr { Ipv6Addr { inner: addr } } } + +// Tests for this module +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io; + use net::*; + use net::Ipv6MulticastScope::*; + use net::test::{tsa, sa6, sa4}; + + #[test] + fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + "2a02:6b8::11:11".parse()); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), + "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + "::FFFF:192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse()); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), + "77.88.21.11:80".parse()); + assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse()); + assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), + "[::127.0.0.1]:22".parse()); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); + } + + #[test] + fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), + "8:9:a:b:c:d:e:f"); + + // reduce a single run of zeros + assert_eq!("ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", + Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); + } + + #[test] + fn ipv4_to_ipv6() { + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()); + } + + #[test] + fn ipv6_to_ipv4() { + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + None); + } + + #[test] + fn ipv4_properties() { + fn check(octets: &[u8; 4], unspec: bool, loopback: bool, + private: bool, link_local: bool, global: bool, + multicast: bool, broadcast: bool, documentation: bool) { + let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]); + assert_eq!(octets, &ip.octets()); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_private(), private); + assert_eq!(ip.is_link_local(), link_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_multicast(), multicast); + assert_eq!(ip.is_broadcast(), broadcast); + assert_eq!(ip.is_documentation(), documentation); + } + + // address unspec loopbk privt linloc global multicast brdcast doc + check(&[0, 0, 0, 0], true, false, false, false, true, false, false, false); + check(&[0, 0, 0, 1], false, false, false, false, true, false, false, false); + check(&[1, 0, 0, 0], false, false, false, false, true, false, false, false); + check(&[10, 9, 8, 7], false, false, true, false, false, false, false, false); + check(&[127, 1, 2, 3], false, true, false, false, false, false, false, false); + check(&[172, 31, 254, 253], false, false, true, false, false, false, false, false); + check(&[169, 254, 253, 242], false, false, false, true, false, false, false, false); + check(&[192, 168, 254, 253], false, false, true, false, false, false, false, false); + check(&[224, 0, 0, 0], false, false, false, false, true, true, false, false); + check(&[239, 255, 255, 255], false, false, false, false, true, true, false, false); + check(&[255, 255, 255, 255], false, false, false, false, false, false, true, false); + check(&[198, 51, 100, 0], false, false, false, false, false, false, false, true); + } + + #[test] + fn ipv6_properties() { + fn check(str_addr: &str, unspec: bool, loopback: bool, + unique_local: bool, global: bool, + u_link_local: bool, u_site_local: bool, u_global: bool, + m_scope: Option) { + let ip: Ipv6Addr = str_addr.parse().unwrap(); + assert_eq!(str_addr, ip.to_string()); + + assert_eq!(ip.is_unspecified(), unspec); + assert_eq!(ip.is_loopback(), loopback); + assert_eq!(ip.is_unique_local(), unique_local); + assert_eq!(ip.is_global(), global); + assert_eq!(ip.is_unicast_link_local(), u_link_local); + assert_eq!(ip.is_unicast_site_local(), u_site_local); + assert_eq!(ip.is_unicast_global(), u_global); + assert_eq!(ip.multicast_scope(), m_scope); + assert_eq!(ip.is_multicast(), m_scope.is_some()); + } + + // unspec loopbk uniqlo global unill unisl uniglo mscope + check("::", + true, false, false, true, false, false, true, None); + check("::1", + false, true, false, false, false, false, false, None); + check("::0.0.0.2", + false, false, false, true, false, false, true, None); + check("1::", + false, false, false, true, false, false, true, None); + check("fc00::", + false, false, true, false, false, false, false, None); + check("fdff:ffff::", + false, false, true, false, false, false, false, None); + check("fe80:ffff::", + false, false, false, false, true, false, false, None); + check("febf:ffff::", + false, false, false, false, true, false, false, None); + check("fec0::", + false, false, false, false, false, true, false, None); + check("ff01::", + false, false, false, false, false, false, false, Some(InterfaceLocal)); + check("ff02::", + false, false, false, false, false, false, false, Some(LinkLocal)); + check("ff03::", + false, false, false, false, false, false, false, Some(RealmLocal)); + check("ff04::", + false, false, false, false, false, false, false, Some(AdminLocal)); + check("ff05::", + false, false, false, false, false, false, false, Some(SiteLocal)); + check("ff08::", + false, false, false, false, false, false, false, Some(OrganizationLocal)); + check("ff0e::", + false, false, false, true, false, false, false, Some(Global)); + } + + #[test] + fn to_socket_addr_socketaddr() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); + } +} diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs index a152b98822..3bfc764e54 100644 --- a/src/libstd/net/mod.rs +++ b/src/libstd/net/mod.rs @@ -18,8 +18,6 @@ use prelude::v1::*; use io::{self, Error, ErrorKind}; -#[allow(deprecated)] // Int -use num::Int; use sys_common::net2 as net_imp; pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; @@ -55,10 +53,21 @@ pub enum Shutdown { Both, } -#[allow(deprecated)] // Int -fn hton(i: I) -> I { i.to_be() } -#[allow(deprecated)] // Int -fn ntoh(i: I) -> I { Int::from_be(i) } +#[doc(hidden)] +trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +fn hton(i: I) -> I { i.to_be() } +fn ntoh(i: I) -> I { I::from_be(i) } fn each_addr(addr: A, mut f: F) -> io::Result where F: FnMut(&SocketAddr) -> io::Result diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 04d1013af1..e48d0e6008 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -27,7 +27,6 @@ use sys_common::{AsInner, FromInner}; /// # Examples /// /// ```no_run -/// # #![feature(net)] /// use std::io::prelude::*; /// use std::net::TcpStream; /// @@ -47,7 +46,6 @@ pub struct TcpStream(net_imp::TcpStream); /// # Examples /// /// ```no_run -/// # #![feature(net)] /// use std::net::{TcpListener, TcpStream}; /// use std::thread; /// @@ -84,7 +82,7 @@ pub struct TcpListener(net_imp::TcpListener); pub struct Incoming<'a> { listener: &'a TcpListener } impl TcpStream { - /// Open a TCP connection to a remote host. + /// Opens a TCP connection to a remote host. /// /// `addr` is an address of the remote host. Anything which implements /// `ToSocketAddrs` trait can be supplied for the address; see this trait @@ -106,7 +104,7 @@ impl TcpStream { self.0.socket_addr() } - /// Shut down the read, write, or both halves of this connection. + /// Shuts down the read, write, or both halves of this connection. /// /// This function will cause all pending and future I/O on the specified /// portions to return immediately with an appropriate value (see the @@ -116,7 +114,7 @@ impl TcpStream { self.0.shutdown(how) } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `TcpStream` is a reference to the same stream that this /// object references. Both handles will read and write the same stream of @@ -192,7 +190,7 @@ impl TcpListener { self.0.socket_addr() } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `TcpListener` is a reference to the same socket that this /// object references. Both handles can be used to accept incoming @@ -215,7 +213,7 @@ impl TcpListener { /// Returns an iterator over the connections being received on this /// listener. /// - /// The returned iterator will never returned `None` and will also not yield + /// The returned iterator will never return `None` and will also not yield /// the peer's `SocketAddr` structure. #[stable(feature = "rust1", since = "1.0.0")] pub fn incoming(&self) -> Incoming { diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index 3d42472f0f..d77d6f1d6d 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -11,7 +11,7 @@ use prelude::v1::*; use env; -use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr}; +use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; static PORT: AtomicUsize = ATOMIC_USIZE_INIT; @@ -27,6 +27,21 @@ pub fn next_test_ip6() -> SocketAddr { port, 0, 0)) } +pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr { + SocketAddr::V4(SocketAddrV4::new(a, p)) +} + +pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr { + SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0)) +} + +pub fn tsa(a: A) -> Result, String> { + match a.to_socket_addrs() { + Ok(a) => Ok(a.collect()), + Err(e) => Err(e.to_string()), + } +} + // The bots run multiple builds at the same time, and these builds // all want to use ports. This function figures out which workspace // it is running in and assigns a port range based on it. diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index 7b14e4dbea..1955b89530 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -27,7 +27,6 @@ use sys_common::{AsInner, FromInner}; /// # Examples /// /// ```no_run -/// # #![feature(net)] /// use std::net::UdpSocket; /// /// # fn foo() -> std::io::Result<()> { @@ -86,7 +85,7 @@ impl UdpSocket { self.0.socket_addr() } - /// Create a new independently owned handle to the underlying socket. + /// Creates a new independently owned handle to the underlying socket. /// /// The returned `UdpSocket` is a reference to the same socket that this /// object references. Both handles will read and write the same port, and @@ -101,7 +100,7 @@ impl UdpSocket { self.0.set_broadcast(on) } - /// Set the multicast loop flag to the specified value + /// Sets the multicast loop flag to the specified value /// /// This lets multicast packets loop back to local sockets (if enabled) pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0ae4d3c5bd..0efc04ef83 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -17,18 +17,14 @@ use prelude::v1::*; +use core::num; use intrinsics; use libc::c_int; -use num::{Float, FpCategory}; -use num::strconv; -use num::strconv::ExponentFormat::{ExpNone, ExpDec}; -use num::strconv::SignificantDigits::{DigAll, DigMax, DigExact}; -use num::strconv::SignFormat::SignNeg; - -use core::num; +use num::{FpCategory, ParseFloatError}; +use sys_common::FromInner; -pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; -pub use core::f32::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; +pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON}; +pub use core::f32::{MIN_EXP, MAX_EXP, MIN_10_EXP}; pub use core::f32::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; pub use core::f32::{MIN, MIN_POSITIVE, MAX}; pub use core::f32::consts; @@ -74,294 +70,16 @@ mod cmath { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl Float for f32 { - #[inline] - fn nan() -> f32 { num::Float::nan() } - #[inline] - fn infinity() -> f32 { num::Float::infinity() } - #[inline] - fn neg_infinity() -> f32 { num::Float::neg_infinity() } - #[inline] - fn zero() -> f32 { num::Float::zero() } - #[inline] - fn neg_zero() -> f32 { num::Float::neg_zero() } - #[inline] - fn one() -> f32 { num::Float::one() } - - #[allow(deprecated)] - #[inline] - fn mantissa_digits(unused_self: Option) -> usize { - num::Float::mantissa_digits(unused_self) - } - #[allow(deprecated)] - #[inline] - fn digits(unused_self: Option) -> usize { num::Float::digits(unused_self) } - #[allow(deprecated)] - #[inline] - fn epsilon() -> f32 { num::Float::epsilon() } - #[allow(deprecated)] - #[inline] - fn min_exp(unused_self: Option) -> isize { num::Float::min_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_exp(unused_self: Option) -> isize { num::Float::max_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn min_10_exp(unused_self: Option) -> isize { num::Float::min_10_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_10_exp(unused_self: Option) -> isize { num::Float::max_10_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn min_value() -> f32 { num::Float::min_value() } - #[allow(deprecated)] - #[inline] - fn min_pos_value(unused_self: Option) -> f32 { num::Float::min_pos_value(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_value() -> f32 { num::Float::max_value() } - - #[inline] - fn is_nan(self) -> bool { num::Float::is_nan(self) } - #[inline] - fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - #[inline] - fn is_finite(self) -> bool { num::Float::is_finite(self) } - #[inline] - fn is_normal(self) -> bool { num::Float::is_normal(self) } - #[inline] - fn classify(self) -> FpCategory { num::Float::classify(self) } - - #[inline] - fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - - #[inline] - fn floor(self) -> f32 { num::Float::floor(self) } - #[inline] - fn ceil(self) -> f32 { num::Float::ceil(self) } - #[inline] - fn round(self) -> f32 { num::Float::round(self) } - #[inline] - fn trunc(self) -> f32 { num::Float::trunc(self) } - #[inline] - fn fract(self) -> f32 { num::Float::fract(self) } - - #[inline] - fn abs(self) -> f32 { num::Float::abs(self) } - #[inline] - fn signum(self) -> f32 { num::Float::signum(self) } - #[inline] - fn is_positive(self) -> bool { num::Float::is_positive(self) } - #[inline] - fn is_negative(self) -> bool { num::Float::is_negative(self) } - - #[inline] - fn mul_add(self, a: f32, b: f32) -> f32 { num::Float::mul_add(self, a, b) } - #[inline] - fn recip(self) -> f32 { num::Float::recip(self) } - - #[inline] - fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } - #[inline] - fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) } - - #[inline] - fn sqrt(self) -> f32 { num::Float::sqrt(self) } - #[inline] - fn rsqrt(self) -> f32 { num::Float::rsqrt(self) } - - #[inline] - fn exp(self) -> f32 { num::Float::exp(self) } - #[inline] - fn exp2(self) -> f32 { num::Float::exp2(self) } - #[inline] - fn ln(self) -> f32 { num::Float::ln(self) } - #[inline] - fn log(self, base: f32) -> f32 { num::Float::log(self, base) } - #[inline] - fn log2(self) -> f32 { num::Float::log2(self) } - #[inline] - fn log10(self) -> f32 { num::Float::log10(self) } - #[inline] - fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - #[inline] - fn to_radians(self) -> f32 { num::Float::to_radians(self) } - - /// Constructs a floating point number by multiplying `x` by 2 raised to the - /// power of `exp` - #[inline] - fn ldexp(self, exp: isize) -> f32 { - unsafe { cmath::ldexpf(self, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - #[inline] - fn frexp(self) -> (f32, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexpf(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - #[inline] - fn next_after(self, other: f32) -> f32 { - unsafe { cmath::nextafterf(self, other) } - } - - #[inline] - fn max(self, other: f32) -> f32 { - unsafe { cmath::fmaxf(self, other) } - } - - #[inline] - fn min(self, other: f32) -> f32 { - unsafe { cmath::fminf(self, other) } - } - - #[inline] - fn abs_sub(self, other: f32) -> f32 { - unsafe { cmath::fdimf(self, other) } - } - - #[inline] - fn cbrt(self) -> f32 { - unsafe { cmath::cbrtf(self) } - } - - #[inline] - fn hypot(self, other: f32) -> f32 { - unsafe { cmath::hypotf(self, other) } - } - - #[inline] - fn sin(self) -> f32 { - unsafe { intrinsics::sinf32(self) } - } - - #[inline] - fn cos(self) -> f32 { - unsafe { intrinsics::cosf32(self) } - } - - #[inline] - fn tan(self) -> f32 { - unsafe { cmath::tanf(self) } - } - - #[inline] - fn asin(self) -> f32 { - unsafe { cmath::asinf(self) } - } - - #[inline] - fn acos(self) -> f32 { - unsafe { cmath::acosf(self) } - } - - #[inline] - fn atan(self) -> f32 { - unsafe { cmath::atanf(self) } - } - - #[inline] - fn atan2(self, other: f32) -> f32 { - unsafe { cmath::atan2f(self, other) } - } - - /// Simultaneously computes the sine and cosine of the number - #[inline] - fn sin_cos(self) -> (f32, f32) { - (self.sin(), self.cos()) - } - - /// Returns the exponential of the number, minus `1`, in a way that is - /// accurate even if the number is close to zero - #[inline] - fn exp_m1(self) -> f32 { - unsafe { cmath::expm1f(self) } - } - - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more - /// accurately than if the operations were performed separately - #[inline] - fn ln_1p(self) -> f32 { - unsafe { cmath::log1pf(self) } - } - - #[inline] - fn sinh(self) -> f32 { - unsafe { cmath::sinhf(self) } - } - - #[inline] - fn cosh(self) -> f32 { - unsafe { cmath::coshf(self) } - } - - #[inline] - fn tanh(self) -> f32 { - unsafe { cmath::tanhf(self) } - } - - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` - /// - `NAN` if `self` is `NAN` - #[inline] - fn asinh(self) -> f32 { - match self { - NEG_INFINITY => NEG_INFINITY, - x => (x + ((x * x) + 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `INFINITY` if `self` is `INFINITY` - /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - #[inline] - fn acosh(self) -> f32 { - match self { - x if x < 1.0 => Float::nan(), - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `INFINITY` if `self` is `1.0` - /// - `NEG_INFINITY` if `self` is `-1.0` - /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `INFINITY` and `NEG_INFINITY`) - #[inline] - fn atanh(self) -> f32 { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() - } -} - #[cfg(not(test))] #[lang = "f32"] #[stable(feature = "rust1", since = "1.0.0")] impl f32 { + /// Parses a float as with a given radix + #[unstable(feature = "float_from_str_radix", reason = "recently moved API")] + pub fn from_str_radix(s: &str, radix: u32) -> Result { + num::Float::from_str_radix(s, radix).map_err(FromInner::from_inner) + } + /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -422,7 +140,6 @@ impl f32 { /// [subnormal][subnormal], or `NaN`. /// /// ``` - /// # #![feature(std_misc)] /// use std::f32; /// /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 @@ -528,7 +245,7 @@ impl f32 { #[inline] pub fn round(self) -> f32 { num::Float::round(self) } - /// Return the integer part of a number. + /// Returns the integer part of a number. /// /// ``` /// let f = 3.3_f32; @@ -618,11 +335,6 @@ impl f32 { #[inline] pub fn is_sign_positive(self) -> bool { num::Float::is_positive(self) } - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] - #[inline] - pub fn is_positive(self) -> bool { num::Float::is_positive(self) } - /// Returns `true` if `self`'s sign is negative, including `-0.0` /// and `NEG_INFINITY`. /// @@ -642,11 +354,6 @@ impl f32 { #[inline] pub fn is_sign_negative(self) -> bool { num::Float::is_negative(self) } - #[stable(feature = "rust1", since = "1.0.0")] - #[deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] - #[inline] - pub fn is_negative(self) -> bool { num::Float::is_negative(self) } - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than /// a separate multiplication operation followed by an add. @@ -667,7 +374,7 @@ impl f32 { #[inline] pub fn mul_add(self, a: f32, b: f32) -> f32 { num::Float::mul_add(self, a, b) } - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` /// use std::f32; @@ -681,7 +388,7 @@ impl f32 { #[inline] pub fn recip(self) -> f32 { num::Float::recip(self) } - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// @@ -697,7 +404,7 @@ impl f32 { #[inline] pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. /// /// ``` /// use std::f32; @@ -711,7 +418,7 @@ impl f32 { #[inline] pub fn powf(self, n: f32) -> f32 { num::Float::powf(self, n) } - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. /// @@ -730,24 +437,6 @@ impl f32 { #[inline] pub fn sqrt(self) -> f32 { num::Float::sqrt(self) } - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::f32; - /// - /// let f = 4.0f32; - /// - /// let abs_difference = (f.rsqrt() - 0.5).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - #[deprecated(since = "1.0.0", reason = "use self.sqrt().recip() instead")] - #[inline] - pub fn rsqrt(self) -> f32 { num::Float::rsqrt(self) } - /// Returns `e^(self)`, (the exponential function). /// /// ``` @@ -853,10 +542,10 @@ impl f32 { #[inline] pub fn log10(self) -> f32 { num::Float::log10(self) } - /// Convert radians to degrees. + /// Converts radians to degrees. /// /// ``` - /// # #![feature(std_misc, core)] + /// # #![feature(std_misc)] /// use std::f32::{self, consts}; /// /// let angle = consts::PI; @@ -869,7 +558,7 @@ impl f32 { #[inline] pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - /// Convert degrees to radians. + /// Converts degrees to radians. /// /// ``` /// # #![feature(std_misc)] @@ -987,7 +676,6 @@ impl f32 { /// * Else: `self - other` /// /// ``` - /// # #![feature(std_misc)] /// use std::f32; /// /// let x = 3.0f32; @@ -1005,10 +693,9 @@ impl f32 { unsafe { cmath::fdimf(self, other) } } - /// Take the cubic root of a number. + /// Takes the cubic root of a number. /// /// ``` - /// # #![feature(std_misc)] /// use std::f32; /// /// let x = 8.0f32; @@ -1024,7 +711,7 @@ impl f32 { unsafe { cmath::cbrtf(self) } } - /// Calculate the length of the hypotenuse of a right-angle triangle given + /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// /// ``` @@ -1210,8 +897,6 @@ impl f32 { /// number is close to zero. /// /// ``` - /// use std::f64; - /// /// let x = 7.0f64; /// /// // e^(ln(7)) - 1 @@ -1344,7 +1029,7 @@ impl f32 { #[inline] pub fn acosh(self) -> f32 { match self { - x if x < 1.0 => Float::nan(), + x if x < 1.0 => ::f32::NAN, x => (x + ((x * x) - 1.0).sqrt()).ln(), } } @@ -1368,116 +1053,9 @@ impl f32 { } } -// -// Section: String Conversions -// - -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use the ToString trait instead")] -pub fn to_string(num: f32) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigAll, ExpNone, false); - r -} - -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use format! instead")] -pub fn to_str_hex(num: f32) -> String { - let (r, _) = strconv::float_to_str_common( - num, 16, true, SignNeg, DigAll, ExpNone, false); - r -} - -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use format! instead")] -pub fn to_str_radix_special(num: f32, rdx: u32) -> (String, bool) { - strconv::float_to_str_common(num, rdx, true, SignNeg, DigAll, ExpNone, false) -} - -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exact(num: f32, dig: usize) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigExact(dig), ExpNone, false); - r -} - -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_digits(num: f32, dig: usize) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigMax(dig), ExpNone, false); - r -} - -/// Converts a float to a string using the exponential notation with exactly the number of -/// provided digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exp_exact(num: f32, dig: usize, upper: bool) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigExact(dig), ExpDec, upper); - r -} - -/// Converts a float to a string using the exponential notation with the maximum number of -/// digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exp_digits(num: f32, dig: usize, upper: bool) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigMax(dig), ExpDec, upper); - r -} - #[cfg(test)] mod tests { + use f32; use f32::*; use num::*; use num::FpCategory as Fp; @@ -1501,7 +1079,7 @@ mod tests { #[test] fn test_nan() { - let nan: f32 = Float::nan(); + let nan: f32 = f32::NAN; assert!(nan.is_nan()); assert!(!nan.is_infinite()); assert!(!nan.is_finite()); @@ -1513,7 +1091,7 @@ mod tests { #[test] fn test_infinity() { - let inf: f32 = Float::infinity(); + let inf: f32 = f32::INFINITY; assert!(inf.is_infinite()); assert!(!inf.is_finite()); assert!(inf.is_sign_positive()); @@ -1525,7 +1103,7 @@ mod tests { #[test] fn test_neg_infinity() { - let neg_inf: f32 = Float::neg_infinity(); + let neg_inf: f32 = f32::NEG_INFINITY; assert!(neg_inf.is_infinite()); assert!(!neg_inf.is_finite()); assert!(!neg_inf.is_sign_positive()); @@ -1537,7 +1115,7 @@ mod tests { #[test] fn test_zero() { - let zero: f32 = Float::zero(); + let zero: f32 = 0.0f32; assert_eq!(0.0, zero); assert!(!zero.is_infinite()); assert!(zero.is_finite()); @@ -1550,7 +1128,7 @@ mod tests { #[test] fn test_neg_zero() { - let neg_zero: f32 = Float::neg_zero(); + let neg_zero: f32 = -0.0; assert_eq!(0.0, neg_zero); assert!(!neg_zero.is_infinite()); assert!(neg_zero.is_finite()); @@ -1563,7 +1141,7 @@ mod tests { #[test] fn test_one() { - let one: f32 = Float::one(); + let one: f32 = 1.0f32; assert_eq!(1.0, one); assert!(!one.is_infinite()); assert!(one.is_finite()); @@ -1576,9 +1154,9 @@ mod tests { #[test] fn test_is_nan() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert!(nan.is_nan()); assert!(!0.0f32.is_nan()); assert!(!5.3f32.is_nan()); @@ -1589,9 +1167,9 @@ mod tests { #[test] fn test_is_infinite() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert!(!nan.is_infinite()); assert!(inf.is_infinite()); assert!(neg_inf.is_infinite()); @@ -1602,9 +1180,9 @@ mod tests { #[test] fn test_is_finite() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert!(!nan.is_finite()); assert!(!inf.is_finite()); assert!(!neg_inf.is_finite()); @@ -1615,11 +1193,11 @@ mod tests { #[test] fn test_is_normal() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let zero: f32 = Float::zero(); - let neg_zero: f32 = Float::neg_zero(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; assert!(!nan.is_normal()); assert!(!inf.is_normal()); assert!(!neg_inf.is_normal()); @@ -1632,11 +1210,11 @@ mod tests { #[test] fn test_classify() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let zero: f32 = Float::zero(); - let neg_zero: f32 = Float::neg_zero(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; assert_eq!(nan.classify(), Fp::Nan); assert_eq!(inf.classify(), Fp::Infinite); assert_eq!(neg_inf.classify(), Fp::Infinite); @@ -1779,9 +1357,9 @@ mod tests { #[test] fn test_mul_add() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); @@ -1795,9 +1373,9 @@ mod tests { #[test] fn test_recip() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(1.0f32.recip(), 1.0); assert_eq!(2.0f32.recip(), 0.5); assert_eq!((-0.4f32).recip(), -2.5); @@ -1809,9 +1387,9 @@ mod tests { #[test] fn test_powi() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(1.0f32.powi(1), 1.0); assert_approx_eq!((-3.1f32).powi(2), 9.61); assert_approx_eq!(5.9f32.powi(-2), 0.028727); @@ -1823,9 +1401,9 @@ mod tests { #[test] fn test_powf() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(1.0f32.powf(1.0), 1.0); assert_approx_eq!(3.4f32.powf(4.5), 246.408218); assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); @@ -1848,30 +1426,15 @@ mod tests { assert_eq!(INFINITY.sqrt(), INFINITY); } - #[test] - fn test_rsqrt() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - assert!(nan.rsqrt().is_nan()); - assert_eq!(inf.rsqrt(), 0.0); - assert!(neg_inf.rsqrt().is_nan()); - assert!((-1.0f32).rsqrt().is_nan()); - assert_eq!((-0.0f32).rsqrt(), neg_inf); - assert_eq!(0.0f32.rsqrt(), inf); - assert_eq!(1.0f32.rsqrt(), 1.0); - assert_eq!(4.0f32.rsqrt(), 0.5); - } - #[test] fn test_exp() { assert_eq!(1.0, 0.0f32.exp()); assert_approx_eq!(2.718282, 1.0f32.exp()); assert_approx_eq!(148.413162, 5.0f32.exp()); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; assert_eq!(inf, inf.exp()); assert_eq!(0.0, neg_inf.exp()); assert!(nan.exp().is_nan()); @@ -1882,9 +1445,9 @@ mod tests { assert_eq!(32.0, 5.0f32.exp2()); assert_eq!(1.0, 0.0f32.exp2()); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; assert_eq!(inf, inf.exp2()); assert_eq!(0.0, neg_inf.exp2()); assert!(nan.exp2().is_nan()); @@ -1892,9 +1455,9 @@ mod tests { #[test] fn test_ln() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_approx_eq!(1.0f32.exp().ln(), 1.0); assert!(nan.ln().is_nan()); assert_eq!(inf.ln(), inf); @@ -1907,12 +1470,12 @@ mod tests { #[test] fn test_log() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(10.0f32.log(10.0), 1.0); assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0.exp()), 1.0); + assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); assert!(1.0f32.log(1.0).is_nan()); assert!(1.0f32.log(-13.9).is_nan()); assert!(nan.log(2.3).is_nan()); @@ -1925,9 +1488,9 @@ mod tests { #[test] fn test_log2() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_approx_eq!(10.0f32.log2(), 3.321928); assert_approx_eq!(2.3f32.log2(), 1.201634); assert_approx_eq!(1.0f32.exp().log2(), 1.442695); @@ -1941,9 +1504,9 @@ mod tests { #[test] fn test_log10() { - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(10.0f32.log10(), 1.0); assert_approx_eq!(2.3f32.log10(), 0.361728); assert_approx_eq!(1.0f32.exp().log10(), 0.434294); @@ -1959,9 +1522,9 @@ mod tests { #[test] fn test_to_degrees() { let pi: f32 = consts::PI; - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(0.0f32.to_degrees(), 0.0); assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); assert_eq!(pi.to_degrees(), 180.0); @@ -1973,9 +1536,9 @@ mod tests { #[test] fn test_to_radians() { let pi: f32 = consts::PI; - let nan: f32 = Float::nan(); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; assert_eq!(0.0f32.to_radians(), 0.0); assert_approx_eq!(154.6f32.to_radians(), 2.698279); assert_approx_eq!((-332.31f32).to_radians(), -5.799903); @@ -1989,40 +1552,40 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); - let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); - let f3: f32 = FromStrRadix::from_str_radix("1.Cp-12", 16).unwrap(); - assert_eq!(1f32.ldexp(-123), f1); - assert_eq!(1f32.ldexp(-111), f2); - assert_eq!(Float::ldexp(1.75f32, -12), f3); + let f1: f32 = f32::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = f32::from_str_radix("1p-111", 16).unwrap(); + let f3: f32 = f32::from_str_radix("1.Cp-12", 16).unwrap(); + assert_eq!(f32::ldexp(1f32, -123), f1); + assert_eq!(f32::ldexp(1f32, -111), f2); + assert_eq!(f32::ldexp(1.75f32, -12), f3); - assert_eq!(Float::ldexp(0f32, -123), 0f32); - assert_eq!(Float::ldexp(-0f32, -123), -0f32); + assert_eq!(f32::ldexp(0f32, -123), 0f32); + assert_eq!(f32::ldexp(-0f32, -123), -0f32); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); - assert_eq!(Float::ldexp(inf, -123), inf); - assert_eq!(Float::ldexp(neg_inf, -123), neg_inf); - assert!(Float::ldexp(nan, -123).is_nan()); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(f32::ldexp(inf, -123), inf); + assert_eq!(f32::ldexp(neg_inf, -123), neg_inf); + assert!(f32::ldexp(nan, -123).is_nan()); } #[test] fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); - let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); - let f3: f32 = FromStrRadix::from_str_radix("1.Cp-123", 16).unwrap(); + let f1: f32 = f32::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = f32::from_str_radix("1p-111", 16).unwrap(); + let f3: f32 = f32::from_str_radix("1.Cp-123", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); let (x3, exp3) = f3.frexp(); assert_eq!((x1, exp1), (0.5f32, -122)); assert_eq!((x2, exp2), (0.5f32, -110)); assert_eq!((x3, exp3), (0.875f32, -122)); - assert_eq!(Float::ldexp(x1, exp1), f1); - assert_eq!(Float::ldexp(x2, exp2), f2); - assert_eq!(Float::ldexp(x3, exp3), f3); + assert_eq!(f32::ldexp(x1, exp1), f1); + assert_eq!(f32::ldexp(x2, exp2), f2); + assert_eq!(f32::ldexp(x3, exp3), f3); assert_eq!(0f32.frexp(), (0f32, 0)); assert_eq!((-0f32).frexp(), (-0f32, 0)); @@ -2030,9 +1593,9 @@ mod tests { #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 fn test_frexp_nowin() { - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; assert_eq!(match inf.frexp() { (x, _) => x }, inf); assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); assert!(match nan.frexp() { (x, _) => x.is_nan() }) @@ -2061,9 +1624,9 @@ mod tests { assert_eq!(0.0f32.asinh(), 0.0f32); assert_eq!((-0.0f32).asinh(), -0.0f32); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); @@ -2076,9 +1639,9 @@ mod tests { assert_eq!(1.0f32.acosh(), 0.0f32); assert!(0.999f32.acosh().is_nan()); - let inf: f32 = Float::infinity(); - let neg_inf: f32 = Float::neg_infinity(); - let nan: f32 = Float::nan(); + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; assert_eq!(inf.acosh(), inf); assert!(neg_inf.acosh().is_nan()); assert!(nan.acosh().is_nan()); @@ -2091,17 +1654,17 @@ mod tests { assert_eq!(0.0f32.atanh(), 0.0f32); assert_eq!((-0.0f32).atanh(), -0.0f32); - let inf32: f32 = Float::infinity(); - let neg_inf32: f32 = Float::neg_infinity(); + let inf32: f32 = f32::INFINITY; + let neg_inf32: f32 = f32::NEG_INFINITY; assert_eq!(1.0f32.atanh(), inf32); assert_eq!((-1.0f32).atanh(), neg_inf32); assert!(2f64.atanh().atanh().is_nan()); assert!((-2f64).atanh().atanh().is_nan()); - let inf64: f32 = Float::infinity(); - let neg_inf64: f32 = Float::neg_infinity(); - let nan32: f32 = Float::nan(); + let inf64: f32 = f32::INFINITY; + let neg_inf64: f32 = f32::NEG_INFINITY; + let nan32: f32 = f32::NAN; assert!(inf64.atanh().is_nan()); assert!(neg_inf64.atanh().is_nan()); assert!(nan32.atanh().is_nan()); @@ -2123,9 +1686,9 @@ mod tests { let frac_pi_8: f32 = consts::FRAC_PI_8; let frac_1_pi: f32 = consts::FRAC_1_PI; let frac_2_pi: f32 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRTPI; - let sqrt2: f32 = consts::SQRT2; - let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT2; + let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; + let sqrt2: f32 = consts::SQRT_2; + let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; let e: f32 = consts::E; let log2_e: f32 = consts::LOG2_E; let log10_e: f32 = consts::LOG10_E; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 794853f6f7..e1497f3958 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -16,18 +16,14 @@ use prelude::v1::*; +use core::num; use intrinsics; use libc::c_int; -use num::{Float, FpCategory}; -use num::strconv; -use num::strconv::ExponentFormat::{ExpNone, ExpDec}; -use num::strconv::SignificantDigits::{DigAll, DigMax, DigExact}; -use num::strconv::SignFormat::SignNeg; - -use core::num; +use num::{FpCategory, ParseFloatError}; +use sys_common::FromInner; -pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; -pub use core::f64::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; +pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON}; +pub use core::f64::{MIN_EXP, MAX_EXP, MIN_10_EXP}; pub use core::f64::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; @@ -82,295 +78,16 @@ mod cmath { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl Float for f64 { - // inlined methods from `num::Float` - #[inline] - fn nan() -> f64 { num::Float::nan() } - #[inline] - fn infinity() -> f64 { num::Float::infinity() } - #[inline] - fn neg_infinity() -> f64 { num::Float::neg_infinity() } - #[inline] - fn zero() -> f64 { num::Float::zero() } - #[inline] - fn neg_zero() -> f64 { num::Float::neg_zero() } - #[inline] - fn one() -> f64 { num::Float::one() } - - - #[allow(deprecated)] - #[inline] - fn mantissa_digits(unused_self: Option) -> usize { - num::Float::mantissa_digits(unused_self) - } - #[allow(deprecated)] - #[inline] - fn digits(unused_self: Option) -> usize { num::Float::digits(unused_self) } - #[allow(deprecated)] - #[inline] - fn epsilon() -> f64 { num::Float::epsilon() } - #[allow(deprecated)] - #[inline] - fn min_exp(unused_self: Option) -> isize { num::Float::min_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_exp(unused_self: Option) -> isize { num::Float::max_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn min_10_exp(unused_self: Option) -> isize { num::Float::min_10_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_10_exp(unused_self: Option) -> isize { num::Float::max_10_exp(unused_self) } - #[allow(deprecated)] - #[inline] - fn min_value() -> f64 { num::Float::min_value() } - #[allow(deprecated)] - #[inline] - fn min_pos_value(unused_self: Option) -> f64 { num::Float::min_pos_value(unused_self) } - #[allow(deprecated)] - #[inline] - fn max_value() -> f64 { num::Float::max_value() } - - #[inline] - fn is_nan(self) -> bool { num::Float::is_nan(self) } - #[inline] - fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - #[inline] - fn is_finite(self) -> bool { num::Float::is_finite(self) } - #[inline] - fn is_normal(self) -> bool { num::Float::is_normal(self) } - #[inline] - fn classify(self) -> FpCategory { num::Float::classify(self) } - - #[inline] - fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) } - - #[inline] - fn floor(self) -> f64 { num::Float::floor(self) } - #[inline] - fn ceil(self) -> f64 { num::Float::ceil(self) } - #[inline] - fn round(self) -> f64 { num::Float::round(self) } - #[inline] - fn trunc(self) -> f64 { num::Float::trunc(self) } - #[inline] - fn fract(self) -> f64 { num::Float::fract(self) } - - #[inline] - fn abs(self) -> f64 { num::Float::abs(self) } - #[inline] - fn signum(self) -> f64 { num::Float::signum(self) } - #[inline] - fn is_positive(self) -> bool { num::Float::is_positive(self) } - #[inline] - fn is_negative(self) -> bool { num::Float::is_negative(self) } - - #[inline] - fn mul_add(self, a: f64, b: f64) -> f64 { num::Float::mul_add(self, a, b) } - #[inline] - fn recip(self) -> f64 { num::Float::recip(self) } - - #[inline] - fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } - #[inline] - fn powf(self, n: f64) -> f64 { num::Float::powf(self, n) } - - #[inline] - fn sqrt(self) -> f64 { num::Float::sqrt(self) } - #[inline] - fn rsqrt(self) -> f64 { num::Float::rsqrt(self) } - - #[inline] - fn exp(self) -> f64 { num::Float::exp(self) } - #[inline] - fn exp2(self) -> f64 { num::Float::exp2(self) } - #[inline] - fn ln(self) -> f64 { num::Float::ln(self) } - #[inline] - fn log(self, base: f64) -> f64 { num::Float::log(self, base) } - #[inline] - fn log2(self) -> f64 { num::Float::log2(self) } - #[inline] - fn log10(self) -> f64 { num::Float::log10(self) } - - #[inline] - fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - #[inline] - fn to_radians(self) -> f64 { num::Float::to_radians(self) } - - #[inline] - fn ldexp(self, exp: isize) -> f64 { - unsafe { cmath::ldexp(self, exp as c_int) } - } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - #[inline] - fn frexp(self) -> (f64, isize) { - unsafe { - let mut exp = 0; - let x = cmath::frexp(self, &mut exp); - (x, exp as isize) - } - } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - #[inline] - fn next_after(self, other: f64) -> f64 { - unsafe { cmath::nextafter(self, other) } - } - - #[inline] - fn max(self, other: f64) -> f64 { - unsafe { cmath::fmax(self, other) } - } - - #[inline] - fn min(self, other: f64) -> f64 { - unsafe { cmath::fmin(self, other) } - } - - #[inline] - fn abs_sub(self, other: f64) -> f64 { - unsafe { cmath::fdim(self, other) } - } - - #[inline] - fn cbrt(self) -> f64 { - unsafe { cmath::cbrt(self) } - } - - #[inline] - fn hypot(self, other: f64) -> f64 { - unsafe { cmath::hypot(self, other) } - } - - #[inline] - fn sin(self) -> f64 { - unsafe { intrinsics::sinf64(self) } - } - - #[inline] - fn cos(self) -> f64 { - unsafe { intrinsics::cosf64(self) } - } - - #[inline] - fn tan(self) -> f64 { - unsafe { cmath::tan(self) } - } - - #[inline] - fn asin(self) -> f64 { - unsafe { cmath::asin(self) } - } - - #[inline] - fn acos(self) -> f64 { - unsafe { cmath::acos(self) } - } - - #[inline] - fn atan(self) -> f64 { - unsafe { cmath::atan(self) } - } - - #[inline] - fn atan2(self, other: f64) -> f64 { - unsafe { cmath::atan2(self, other) } - } - - /// Simultaneously computes the sine and cosine of the number - #[inline] - fn sin_cos(self) -> (f64, f64) { - (self.sin(), self.cos()) - } - - /// Returns the exponential of the number, minus `1`, in a way that is - /// accurate even if the number is close to zero - #[inline] - fn exp_m1(self) -> f64 { - unsafe { cmath::expm1(self) } - } - - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more - /// accurately than if the operations were performed separately - #[inline] - fn ln_1p(self) -> f64 { - unsafe { cmath::log1p(self) } - } - - #[inline] - fn sinh(self) -> f64 { - unsafe { cmath::sinh(self) } - } - - #[inline] - fn cosh(self) -> f64 { - unsafe { cmath::cosh(self) } - } - - #[inline] - fn tanh(self) -> f64 { - unsafe { cmath::tanh(self) } - } - - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` - /// - `NAN` if `self` is `NAN` - #[inline] - fn asinh(self) -> f64 { - match self { - NEG_INFINITY => NEG_INFINITY, - x => (x + ((x * x) + 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `INFINITY` if `self` is `INFINITY` - /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - #[inline] - fn acosh(self) -> f64 { - match self { - x if x < 1.0 => Float::nan(), - x => (x + ((x * x) - 1.0).sqrt()).ln(), - } - } - - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `INFINITY` if `self` is `1.0` - /// - `NEG_INFINITY` if `self` is `-1.0` - /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `INFINITY` and `NEG_INFINITY`) - #[inline] - fn atanh(self) -> f64 { - 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() - } -} - #[cfg(not(test))] #[lang = "f64"] #[stable(feature = "rust1", since = "1.0.0")] impl f64 { + /// Parses a float as with a given radix + #[unstable(feature = "float_from_str_radix", reason = "recently moved API")] + pub fn from_str_radix(s: &str, radix: u32) -> Result { + num::Float::from_str_radix(s, radix).map_err(FromInner::from_inner) + } + /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -534,7 +251,7 @@ impl f64 { #[inline] pub fn round(self) -> f64 { num::Float::round(self) } - /// Return the integer part of a number. + /// Returns the integer part of a number. /// /// ``` /// let f = 3.3_f64; @@ -671,7 +388,7 @@ impl f64 { #[inline] pub fn mul_add(self, a: f64, b: f64) -> f64 { num::Float::mul_add(self, a, b) } - /// Take the reciprocal (inverse) of a number, `1/x`. + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` /// let x = 2.0_f64; @@ -683,7 +400,7 @@ impl f64 { #[inline] pub fn recip(self) -> f64 { num::Float::recip(self) } - /// Raise a number to an integer power. + /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` /// @@ -697,7 +414,7 @@ impl f64 { #[inline] pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } - /// Raise a number to a floating point power. + /// Raises a number to a floating point power. /// /// ``` /// let x = 2.0_f64; @@ -709,7 +426,7 @@ impl f64 { #[inline] pub fn powf(self, n: f64) -> f64 { num::Float::powf(self, n) } - /// Take the square root of a number. + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. /// @@ -726,22 +443,6 @@ impl f64 { #[inline] pub fn sqrt(self) -> f64 { num::Float::sqrt(self) } - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. - /// - /// ``` - /// # #![feature(std_misc)] - /// let f = 4.0_f64; - /// - /// let abs_difference = (f.rsqrt() - 0.5).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - #[deprecated(since = "1.0.0", reason = "use self.sqrt().recip() instead")] - #[inline] - pub fn rsqrt(self) -> f64 { num::Float::rsqrt(self) } - /// Returns `e^(self)`, (the exponential function). /// /// ``` @@ -835,7 +536,7 @@ impl f64 { #[inline] pub fn log10(self) -> f64 { num::Float::log10(self) } - /// Convert radians to degrees. + /// Converts radians to degrees. /// /// ``` /// use std::f64::consts; @@ -850,7 +551,7 @@ impl f64 { #[inline] pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - /// Convert degrees to radians. + /// Converts degrees to radians. /// /// ``` /// use std::f64::consts; @@ -978,7 +679,7 @@ impl f64 { unsafe { cmath::fdim(self, other) } } - /// Take the cubic root of a number. + /// Takes the cubic root of a number. /// /// ``` /// let x = 8.0_f64; @@ -994,7 +695,7 @@ impl f64 { unsafe { cmath::cbrt(self) } } - /// Calculate the length of the hypotenuse of a right-angle triangle given + /// Calculates the length of the hypotenuse of a right-angle triangle given /// legs of length `x` and `y`. /// /// ``` @@ -1304,7 +1005,7 @@ impl f64 { #[inline] pub fn acosh(self) -> f64 { match self { - x if x < 1.0 => Float::nan(), + x if x < 1.0 => NAN, x => (x + ((x * x) - 1.0).sqrt()).ln(), } } @@ -1328,116 +1029,9 @@ impl f64 { } } -// -// Section: String Conversions -// - -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use the ToString trait instead")] -pub fn to_string(num: f64) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigAll, ExpNone, false); - r -} - -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use format! instead")] -pub fn to_str_hex(num: f64) -> String { - let (r, _) = strconv::float_to_str_common( - num, 16, true, SignNeg, DigAll, ExpNone, false); - r -} - -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -#[deprecated(since = "1.0.0", reason = "use format! instead")] -pub fn to_str_radix_special(num: f64, rdx: u32) -> (String, bool) { - strconv::float_to_str_common(num, rdx, true, SignNeg, DigAll, ExpNone, false) -} - -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exact(num: f64, dig: usize) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigExact(dig), ExpNone, false); - r -} - -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_digits(num: f64, dig: usize) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigMax(dig), ExpNone, false); - r -} - -/// Converts a float to a string using the exponential notation with exactly the number of -/// provided digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exp_exact(num: f64, dig: usize, upper: bool) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigExact(dig), ExpDec, upper); - r -} - -/// Converts a float to a string using the exponential notation with the maximum number of -/// digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[unstable(feature = "std_misc", reason = "may be removed or relocated")] -pub fn to_str_exp_digits(num: f64, dig: usize, upper: bool) -> String { - let (r, _) = strconv::float_to_str_common( - num, 10, true, SignNeg, DigMax(dig), ExpDec, upper); - r -} - #[cfg(test)] mod tests { + use f64; use f64::*; use num::*; use num::FpCategory as Fp; @@ -1461,7 +1055,7 @@ mod tests { #[test] fn test_nan() { - let nan: f64 = Float::nan(); + let nan: f64 = NAN; assert!(nan.is_nan()); assert!(!nan.is_infinite()); assert!(!nan.is_finite()); @@ -1473,7 +1067,7 @@ mod tests { #[test] fn test_infinity() { - let inf: f64 = Float::infinity(); + let inf: f64 = INFINITY; assert!(inf.is_infinite()); assert!(!inf.is_finite()); assert!(inf.is_sign_positive()); @@ -1485,7 +1079,7 @@ mod tests { #[test] fn test_neg_infinity() { - let neg_inf: f64 = Float::neg_infinity(); + let neg_inf: f64 = NEG_INFINITY; assert!(neg_inf.is_infinite()); assert!(!neg_inf.is_finite()); assert!(!neg_inf.is_sign_positive()); @@ -1497,7 +1091,7 @@ mod tests { #[test] fn test_zero() { - let zero: f64 = Float::zero(); + let zero: f64 = 0.0f64; assert_eq!(0.0, zero); assert!(!zero.is_infinite()); assert!(zero.is_finite()); @@ -1510,7 +1104,7 @@ mod tests { #[test] fn test_neg_zero() { - let neg_zero: f64 = Float::neg_zero(); + let neg_zero: f64 = -0.0; assert_eq!(0.0, neg_zero); assert!(!neg_zero.is_infinite()); assert!(neg_zero.is_finite()); @@ -1523,7 +1117,7 @@ mod tests { #[test] fn test_one() { - let one: f64 = Float::one(); + let one: f64 = 1.0f64; assert_eq!(1.0, one); assert!(!one.is_infinite()); assert!(one.is_finite()); @@ -1536,9 +1130,9 @@ mod tests { #[test] fn test_is_nan() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert!(nan.is_nan()); assert!(!0.0f64.is_nan()); assert!(!5.3f64.is_nan()); @@ -1549,9 +1143,9 @@ mod tests { #[test] fn test_is_infinite() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert!(!nan.is_infinite()); assert!(inf.is_infinite()); assert!(neg_inf.is_infinite()); @@ -1562,9 +1156,9 @@ mod tests { #[test] fn test_is_finite() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert!(!nan.is_finite()); assert!(!inf.is_finite()); assert!(!neg_inf.is_finite()); @@ -1575,11 +1169,11 @@ mod tests { #[test] fn test_is_normal() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let zero: f64 = Float::zero(); - let neg_zero: f64 = Float::neg_zero(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; assert!(!nan.is_normal()); assert!(!inf.is_normal()); assert!(!neg_inf.is_normal()); @@ -1592,11 +1186,11 @@ mod tests { #[test] fn test_classify() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let zero: f64 = Float::zero(); - let neg_zero: f64 = Float::neg_zero(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; assert_eq!(nan.classify(), Fp::Nan); assert_eq!(inf.classify(), Fp::Infinite); assert_eq!(neg_inf.classify(), Fp::Infinite); @@ -1738,9 +1332,9 @@ mod tests { #[test] fn test_mul_add() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); @@ -1754,9 +1348,9 @@ mod tests { #[test] fn test_recip() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(1.0f64.recip(), 1.0); assert_eq!(2.0f64.recip(), 0.5); assert_eq!((-0.4f64).recip(), -2.5); @@ -1768,9 +1362,9 @@ mod tests { #[test] fn test_powi() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(1.0f64.powi(1), 1.0); assert_approx_eq!((-3.1f64).powi(2), 9.61); assert_approx_eq!(5.9f64.powi(-2), 0.028727); @@ -1782,9 +1376,9 @@ mod tests { #[test] fn test_powf() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(1.0f64.powf(1.0), 1.0); assert_approx_eq!(3.4f64.powf(4.5), 246.408183); assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); @@ -1807,30 +1401,15 @@ mod tests { assert_eq!(INFINITY.sqrt(), INFINITY); } - #[test] - fn test_rsqrt() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - assert!(nan.rsqrt().is_nan()); - assert_eq!(inf.rsqrt(), 0.0); - assert!(neg_inf.rsqrt().is_nan()); - assert!((-1.0f64).rsqrt().is_nan()); - assert_eq!((-0.0f64).rsqrt(), neg_inf); - assert_eq!(0.0f64.rsqrt(), inf); - assert_eq!(1.0f64.rsqrt(), 1.0); - assert_eq!(4.0f64.rsqrt(), 0.5); - } - #[test] fn test_exp() { assert_eq!(1.0, 0.0f64.exp()); assert_approx_eq!(2.718282, 1.0f64.exp()); assert_approx_eq!(148.413159, 5.0f64.exp()); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(inf, inf.exp()); assert_eq!(0.0, neg_inf.exp()); assert!(nan.exp().is_nan()); @@ -1841,9 +1420,9 @@ mod tests { assert_eq!(32.0, 5.0f64.exp2()); assert_eq!(1.0, 0.0f64.exp2()); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(inf, inf.exp2()); assert_eq!(0.0, neg_inf.exp2()); assert!(nan.exp2().is_nan()); @@ -1851,9 +1430,9 @@ mod tests { #[test] fn test_ln() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_approx_eq!(1.0f64.exp().ln(), 1.0); assert!(nan.ln().is_nan()); assert_eq!(inf.ln(), inf); @@ -1866,12 +1445,12 @@ mod tests { #[test] fn test_log() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(10.0f64.log(10.0), 1.0); assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0.exp()), 1.0); + assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); assert!(1.0f64.log(1.0).is_nan()); assert!(1.0f64.log(-13.9).is_nan()); assert!(nan.log(2.3).is_nan()); @@ -1884,9 +1463,9 @@ mod tests { #[test] fn test_log2() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_approx_eq!(10.0f64.log2(), 3.321928); assert_approx_eq!(2.3f64.log2(), 1.201634); assert_approx_eq!(1.0f64.exp().log2(), 1.442695); @@ -1900,9 +1479,9 @@ mod tests { #[test] fn test_log10() { - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(10.0f64.log10(), 1.0); assert_approx_eq!(2.3f64.log10(), 0.361728); assert_approx_eq!(1.0f64.exp().log10(), 0.434294); @@ -1918,9 +1497,9 @@ mod tests { #[test] fn test_to_degrees() { let pi: f64 = consts::PI; - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(0.0f64.to_degrees(), 0.0); assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); assert_eq!(pi.to_degrees(), 180.0); @@ -1932,9 +1511,9 @@ mod tests { #[test] fn test_to_radians() { let pi: f64 = consts::PI; - let nan: f64 = Float::nan(); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let nan: f64 = NAN; + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; assert_eq!(0.0f64.to_radians(), 0.0); assert_approx_eq!(154.6f64.to_radians(), 2.698279); assert_approx_eq!((-332.31f64).to_radians(), -5.799903); @@ -1948,40 +1527,40 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); - let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); - let f3: f64 = FromStrRadix::from_str_radix("1.Cp-12", 16).unwrap(); - assert_eq!(1f64.ldexp(-123), f1); - assert_eq!(1f64.ldexp(-111), f2); - assert_eq!(Float::ldexp(1.75f64, -12), f3); + let f1: f64 = f64::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = f64::from_str_radix("1p-111", 16).unwrap(); + let f3: f64 = f64::from_str_radix("1.Cp-12", 16).unwrap(); + assert_eq!(f64::ldexp(1f64, -123), f1); + assert_eq!(f64::ldexp(1f64, -111), f2); + assert_eq!(f64::ldexp(1.75f64, -12), f3); - assert_eq!(Float::ldexp(0f64, -123), 0f64); - assert_eq!(Float::ldexp(-0f64, -123), -0f64); + assert_eq!(f64::ldexp(0f64, -123), 0f64); + assert_eq!(f64::ldexp(-0f64, -123), -0f64); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); - assert_eq!(Float::ldexp(inf, -123), inf); - assert_eq!(Float::ldexp(neg_inf, -123), neg_inf); - assert!(Float::ldexp(nan, -123).is_nan()); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; + assert_eq!(f64::ldexp(inf, -123), inf); + assert_eq!(f64::ldexp(neg_inf, -123), neg_inf); + assert!(f64::ldexp(nan, -123).is_nan()); } #[test] fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); - let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); - let f3: f64 = FromStrRadix::from_str_radix("1.Cp-123", 16).unwrap(); + let f1: f64 = f64::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = f64::from_str_radix("1p-111", 16).unwrap(); + let f3: f64 = f64::from_str_radix("1.Cp-123", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); let (x3, exp3) = f3.frexp(); assert_eq!((x1, exp1), (0.5f64, -122)); assert_eq!((x2, exp2), (0.5f64, -110)); assert_eq!((x3, exp3), (0.875f64, -122)); - assert_eq!(Float::ldexp(x1, exp1), f1); - assert_eq!(Float::ldexp(x2, exp2), f2); - assert_eq!(Float::ldexp(x3, exp3), f3); + assert_eq!(f64::ldexp(x1, exp1), f1); + assert_eq!(f64::ldexp(x2, exp2), f2); + assert_eq!(f64::ldexp(x3, exp3), f3); assert_eq!(0f64.frexp(), (0f64, 0)); assert_eq!((-0f64).frexp(), (-0f64, 0)); @@ -1989,9 +1568,9 @@ mod tests { #[test] #[cfg_attr(windows, ignore)] // FIXME #8755 fn test_frexp_nowin() { - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(match inf.frexp() { (x, _) => x }, inf); assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf); assert!(match nan.frexp() { (x, _) => x.is_nan() }) @@ -2020,9 +1599,9 @@ mod tests { assert_eq!(0.0f64.asinh(), 0.0f64); assert_eq!((-0.0f64).asinh(), -0.0f64); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(inf.asinh(), inf); assert_eq!(neg_inf.asinh(), neg_inf); assert!(nan.asinh().is_nan()); @@ -2035,9 +1614,9 @@ mod tests { assert_eq!(1.0f64.acosh(), 0.0f64); assert!(0.999f64.acosh().is_nan()); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(inf.acosh(), inf); assert!(neg_inf.acosh().is_nan()); assert!(nan.acosh().is_nan()); @@ -2050,9 +1629,9 @@ mod tests { assert_eq!(0.0f64.atanh(), 0.0f64); assert_eq!((-0.0f64).atanh(), -0.0f64); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); - let nan: f64 = Float::nan(); + let inf: f64 = INFINITY; + let neg_inf: f64 = NEG_INFINITY; + let nan: f64 = NAN; assert_eq!(1.0f64.atanh(), inf); assert_eq!((-1.0f64).atanh(), neg_inf); assert!(2f64.atanh().atanh().is_nan()); @@ -2076,9 +1655,9 @@ mod tests { let frac_pi_8: f64 = consts::FRAC_PI_8; let frac_1_pi: f64 = consts::FRAC_1_PI; let frac_2_pi: f64 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRTPI; - let sqrt2: f64 = consts::SQRT2; - let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT2; + let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; + let sqrt2: f64 = consts::SQRT_2; + let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; let e: f64 = consts::E; let log2_e: f64 = consts::LOG2_E; let log10_e: f64 = consts::LOG10_E; diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index 2de03e2e72..cd26be013c 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -15,1134 +15,27 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] -#![allow(deprecated)] -#[cfg(test)] use fmt::Debug; -use ops::{Add, Sub, Mul, Div, Rem, Neg}; +use fmt; +use core::num; -use marker::Copy; -use clone::Clone; -use cmp::{PartialOrd, PartialEq}; - -pub use core::num::{Int, SignedInt, Zero, One}; -pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; -pub use core::num::{from_int, from_i8, from_i16, from_i32, from_i64}; -pub use core::num::{from_uint, from_u8, from_u16, from_u32, from_u64}; -pub use core::num::{from_f32, from_f64}; -pub use core::num::{FromStrRadix, from_str_radix}; -pub use core::num::{FpCategory, ParseIntError, ParseFloatError}; +pub use core::num::{Zero, One}; +pub use core::num::{FpCategory, ParseIntError}; pub use core::num::{wrapping, Wrapping}; -use option::Option; - -#[unstable(feature = "std_misc", reason = "likely to be removed")] -pub mod strconv; - -/// Mathematical operations on primitive floating point numbers. -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", - reason = "replaced by inherent methods; use rust-lang/num for generics")] -pub trait Float - : Copy + Clone - + NumCast - + PartialOrd - + PartialEq - + Neg - + Add - + Sub - + Mul - + Div - + Rem -{ - // inlined methods from `num::Float` - /// Returns the `NaN` value. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let nan: f32 = Float::nan(); - /// - /// assert!(nan.is_nan()); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn nan() -> Self; - /// Returns the infinite value. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f32; - /// - /// let infinity: f32 = Float::infinity(); - /// - /// assert!(infinity.is_infinite()); - /// assert!(!infinity.is_finite()); - /// assert!(infinity > f32::MAX); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn infinity() -> Self; - /// Returns the negative infinite value. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f32; - /// - /// let neg_infinity: f32 = Float::neg_infinity(); - /// - /// assert!(neg_infinity.is_infinite()); - /// assert!(!neg_infinity.is_finite()); - /// assert!(neg_infinity < f32::MIN); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn neg_infinity() -> Self; - /// Returns `0.0`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let inf: f32 = Float::infinity(); - /// let zero: f32 = Float::zero(); - /// let neg_zero: f32 = Float::neg_zero(); - /// - /// assert_eq!(zero, neg_zero); - /// assert_eq!(7.0f32/inf, zero); - /// assert_eq!(zero * 10.0, zero); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn zero() -> Self; - /// Returns `-0.0`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let inf: f32 = Float::infinity(); - /// let zero: f32 = Float::zero(); - /// let neg_zero: f32 = Float::neg_zero(); - /// - /// assert_eq!(zero, neg_zero); - /// assert_eq!(7.0f32/inf, zero); - /// assert_eq!(zero * 10.0, zero); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn neg_zero() -> Self; - /// Returns `1.0`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let one: f32 = Float::one(); - /// - /// assert_eq!(one, 1.0f32); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn one() -> Self; - - // FIXME (#5527): These should be associated constants - - /// Deprecated: use `std::f32::MANTISSA_DIGITS` or `std::f64::MANTISSA_DIGITS` - /// instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MANTISSA_DIGITS` or \ - `std::f64::MANTISSA_DIGITS` as appropriate")] - fn mantissa_digits(unused_self: Option) -> usize; - /// Deprecated: use `std::f32::DIGITS` or `std::f64::DIGITS` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::DIGITS` or `std::f64::DIGITS` as appropriate")] - fn digits(unused_self: Option) -> usize; - /// Deprecated: use `std::f32::EPSILON` or `std::f64::EPSILON` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::EPSILON` or `std::f64::EPSILON` as appropriate")] - fn epsilon() -> Self; - /// Deprecated: use `std::f32::MIN_EXP` or `std::f64::MIN_EXP` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN_EXP` or `std::f64::MIN_EXP` as appropriate")] - fn min_exp(unused_self: Option) -> isize; - /// Deprecated: use `std::f32::MAX_EXP` or `std::f64::MAX_EXP` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MAX_EXP` or `std::f64::MAX_EXP` as appropriate")] - fn max_exp(unused_self: Option) -> isize; - /// Deprecated: use `std::f32::MIN_10_EXP` or `std::f64::MIN_10_EXP` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MIN_10_EXP` or `std::f64::MIN_10_EXP` as appropriate")] - fn min_10_exp(unused_self: Option) -> isize; - /// Deprecated: use `std::f32::MAX_10_EXP` or `std::f64::MAX_10_EXP` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", - reason = "use `std::f32::MAX_10_EXP` or `std::f64::MAX_10_EXP` as appropriate")] - fn max_10_exp(unused_self: Option) -> isize; - - /// Returns the smallest finite value that this type can represent. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x: f64 = Float::min_value(); - /// - /// assert_eq!(x, f64::MIN); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn min_value() -> Self; - /// Returns the smallest normalized positive number that this type can represent. - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn min_pos_value(unused_self: Option) -> Self; - /// Returns the largest finite value that this type can represent. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x: f64 = Float::max_value(); - /// assert_eq!(x, f64::MAX); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn max_value() -> Self; - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f64; - /// - /// let nan = f64::NAN; - /// let f = 7.0; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[unstable(feature = "std_misc", reason = "position is undecided")] - fn is_nan(self) -> bool; - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf: f32 = Float::infinity(); - /// let neg_inf: f32 = Float::neg_infinity(); - /// let nan: f32 = f32::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[unstable(feature = "std_misc", reason = "position is undecided")] - fn is_infinite(self) -> bool; - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf: f32 = Float::infinity(); - /// let neg_inf: f32 = Float::neg_infinity(); - /// let nan: f32 = f32::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[unstable(feature = "std_misc", reason = "position is undecided")] - fn is_finite(self) -> bool; - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f32; - /// - /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 - /// let max = f32::MAX; - /// let lower_than_min = 1.0e-40_f32; - /// let zero = 0.0f32; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f32::NAN.is_normal()); - /// assert!(!f32::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: http://en.wikipedia.org/wiki/Denormal_number - #[unstable(feature = "std_misc", reason = "position is undecided")] - fn is_normal(self) -> bool; - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::{Float, FpCategory}; - /// use std::f32; - /// - /// let num = 12.4f32; - /// let inf = f32::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn classify(self) -> FpCategory; - - /// Returns the mantissa, base 2 exponent, and sign as integers, respectively. - /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`. - /// The floating point encoding is documented in the [Reference][floating-point]. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let num = 2.0f32; - /// - /// // (8388608, -22, 1) - /// let (mantissa, exponent, sign) = num.integer_decode(); - /// let sign_f = sign as f32; - /// let mantissa_f = mantissa as f32; - /// let exponent_f = num.powf(exponent as f32); - /// - /// // 1 * 8388608 * 2^(-22) == 2 - /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - /// [floating-point]: ../../../../../reference.html#machine-types - #[unstable(feature = "std_misc", reason = "signature is undecided")] - fn integer_decode(self) -> (u64, i16, i8); - - /// Returns the largest integer less than or equal to a number. - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 3.99; - /// let g = 3.0; - /// - /// assert_eq!(f.floor(), 3.0); - /// assert_eq!(g.floor(), 3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn floor(self) -> Self; - /// Returns the smallest integer greater than or equal to a number. - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 3.01; - /// let g = 4.0; - /// - /// assert_eq!(f.ceil(), 4.0); - /// assert_eq!(g.ceil(), 4.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn ceil(self) -> Self; - /// Returns the nearest integer to a number. Round half-way cases away from - /// `0.0`. - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 3.3; - /// let g = -3.3; - /// - /// assert_eq!(f.round(), 3.0); - /// assert_eq!(g.round(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn round(self) -> Self; - /// Return the integer part of a number. - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 3.3; - /// let g = -3.7; - /// - /// assert_eq!(f.trunc(), 3.0); - /// assert_eq!(g.trunc(), -3.0); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn trunc(self) -> Self; - /// Returns the fractional part of a number. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 3.5; - /// let y = -3.5; - /// let abs_difference_x = (x.fract() - 0.5).abs(); - /// let abs_difference_y = (y.fract() - (-0.5)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn fract(self) -> Self; - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = 3.5; - /// let y = -3.5; - /// - /// let abs_difference_x = (x.abs() - x).abs(); - /// let abs_difference_y = (y.abs() - (-y)).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// - /// assert!(f64::NAN.abs().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn abs(self) -> Self; - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// use std::f64; - /// - /// let f = 3.5; - /// - /// assert_eq!(f.signum(), 1.0); - /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0); - /// - /// assert!(f64::NAN.signum().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn signum(self) -> Self; - /// Returns `true` if `self` is positive, including `+0.0` and - /// `Float::infinity()`. - /// - /// ``` - /// use std::num::Float; - /// use std::f64; - /// - /// let nan: f64 = f64::NAN; - /// - /// let f = 7.0; - /// let g = -7.0; - /// - /// assert!(f.is_positive()); - /// assert!(!g.is_positive()); - /// // Requires both tests to determine if is `NaN` - /// assert!(!nan.is_positive() && !nan.is_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn is_positive(self) -> bool; - /// Returns `true` if `self` is negative, including `-0.0` and - /// `Float::neg_infinity()`. - /// - /// ``` - /// use std::num::Float; - /// use std::f64; - /// - /// let nan = f64::NAN; - /// - /// let f = 7.0; - /// let g = -7.0; - /// - /// assert!(!f.is_negative()); - /// assert!(g.is_negative()); - /// // Requires both tests to determine if is `NaN`. - /// assert!(!nan.is_positive() && !nan.is_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn is_negative(self) -> bool; - - /// Fused multiply-add. Computes `(self * a) + b` with only one rounding - /// error. This produces a more accurate result with better performance than - /// a separate multiplication operation followed by an add. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let m = 10.0; - /// let x = 4.0; - /// let b = 60.0; - /// - /// // 100.0 - /// let abs_difference = (m.mul_add(x, b) - (m*x + b)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn mul_add(self, a: Self, b: Self) -> Self; - /// Take the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 2.0; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn recip(self) -> Self; - - /// Raise a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 2.0; - /// let abs_difference = (x.powi(2) - x*x).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn powi(self, n: i32) -> Self; - /// Raise a number to a floating point power. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 2.0; - /// let abs_difference = (x.powf(2.0) - x*x).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn powf(self, n: Self) -> Self; - /// Take the square root of a number. - /// - /// Returns NaN if `self` is a negative number. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let positive = 4.0; - /// let negative = -4.0; - /// - /// let abs_difference = (positive.sqrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// assert!(negative.sqrt().is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn sqrt(self) -> Self; - - /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let f = 4.0; - /// - /// let abs_difference = (f.rsqrt() - 0.5).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn rsqrt(self) -> Self; - - /// Returns `e^(self)`, (the exponential function). - /// - /// ``` - /// use std::num::Float; - /// - /// let one = 1.0; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn exp(self) -> Self; - /// Returns `2^(self)`. - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 2.0; - /// - /// // 2^2 - 4 == 0 - /// let abs_difference = (f.exp2() - 4.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn exp2(self) -> Self; - /// Returns the natural logarithm of the number. - /// - /// ``` - /// use std::num::Float; - /// - /// let one = 1.0; - /// // e^1 - /// let e = one.exp(); - /// - /// // ln(e) - 1 == 0 - /// let abs_difference = (e.ln() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn ln(self) -> Self; - /// Returns the logarithm of the number with respect to an arbitrary base. - /// - /// ``` - /// use std::num::Float; - /// - /// let ten = 10.0; - /// let two = 2.0; - /// - /// // log10(10) - 1 == 0 - /// let abs_difference_10 = (ten.log(10.0) - 1.0).abs(); - /// - /// // log2(2) - 1 == 0 - /// let abs_difference_2 = (two.log(2.0) - 1.0).abs(); - /// - /// assert!(abs_difference_10 < 1e-10); - /// assert!(abs_difference_2 < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn log(self, base: Self) -> Self; - /// Returns the base 2 logarithm of the number. - /// - /// ``` - /// use std::num::Float; - /// - /// let two = 2.0; - /// - /// // log2(2) - 1 == 0 - /// let abs_difference = (two.log2() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn log2(self) -> Self; - /// Returns the base 10 logarithm of the number. - /// - /// ``` - /// use std::num::Float; - /// - /// let ten = 10.0; - /// - /// // log10(10) - 1 == 0 - /// let abs_difference = (ten.log10() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn log10(self) -> Self; - - /// Convert radians to degrees. - /// - /// ``` - /// # #![feature(std_misc, core)] - /// use std::num::Float; - /// use std::f64::consts; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "desirability is unclear")] - fn to_degrees(self) -> Self; - /// Convert degrees to radians. - /// - /// ``` - /// # #![feature(std_misc, core)] - /// use std::num::Float; - /// use std::f64::consts; - /// - /// let angle = 180.0; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "desirability is unclear")] - fn to_radians(self) -> Self; - /// Constructs a floating point number of `x*2^exp`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// // 3*2^2 - 12 == 0 - /// let abs_difference = (Float::ldexp(3.0, 2) - 12.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "pending integer conventions")] - fn ldexp(self, exp: isize) -> Self; - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * 2^exp` - /// * `0.5 <= abs(x) < 1.0` - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 4.0; - /// - /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0 - /// let f = x.frexp(); - /// let abs_difference_0 = (f.0 - 0.5).abs(); - /// let abs_difference_1 = (f.1 as f64 - 3.0).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_1 < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "pending integer conventions")] - fn frexp(self) -> (Self, isize); - /// Returns the next representable floating-point value in the direction of - /// `other`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 1.0f32; - /// - /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs(); - /// - /// assert!(abs_diff < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn next_after(self, other: Self) -> Self; - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 1.0; - /// let y = 2.0; - /// - /// assert_eq!(x.max(y), y); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn max(self, other: Self) -> Self; - /// Returns the minimum of the two numbers. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 1.0; - /// let y = 2.0; - /// - /// assert_eq!(x.min(y), x); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn min(self, other: Self) -> Self; - - /// The positive difference of two numbers. - /// - /// * If `self <= other`: `0:0` - /// * Else: `self - other` - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 3.0; - /// let y = -3.0; - /// - /// let abs_difference_x = (x.abs_sub(1.0) - 2.0).abs(); - /// let abs_difference_y = (y.abs_sub(1.0) - 0.0).abs(); - /// - /// assert!(abs_difference_x < 1e-10); - /// assert!(abs_difference_y < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "may be renamed")] - fn abs_sub(self, other: Self) -> Self; - /// Take the cubic root of a number. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 8.0; - /// - /// // x^(1/3) - 2 == 0 - /// let abs_difference = (x.cbrt() - 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "may be renamed")] - fn cbrt(self) -> Self; - /// Calculate the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 2.0; - /// let y = 3.0; - /// - /// // sqrt(x^2 + y^2) - /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", - reason = "unsure about its place in the world")] - fn hypot(self, other: Self) -> Self; - - /// Computes the sine of a number (in radians). - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = f64::consts::PI/2.0; - /// - /// let abs_difference = (x.sin() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn sin(self) -> Self; - /// Computes the cosine of a number (in radians). - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = 2.0*f64::consts::PI; - /// - /// let abs_difference = (x.cos() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn cos(self) -> Self; - /// Computes the tangent of a number (in radians). - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = f64::consts::PI/4.0; - /// let abs_difference = (x.tan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-14); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn tan(self) -> Self; - /// Computes the arcsine of a number. Return value is in radians in - /// the range [-pi/2, pi/2] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let f = f64::consts::PI / 2.0; - /// - /// // asin(sin(pi/2)) - /// let abs_difference = (f.sin().asin() - f64::consts::PI / 2.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn asin(self) -> Self; - /// Computes the arccosine of a number. Return value is in radians in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let f = f64::consts::PI / 4.0; - /// - /// // acos(cos(pi/4)) - /// let abs_difference = (f.cos().acos() - f64::consts::PI / 4.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn acos(self) -> Self; - /// Computes the arctangent of a number. Return value is in radians in the - /// range [-pi/2, pi/2]; - /// - /// ``` - /// use std::num::Float; - /// - /// let f = 1.0; - /// - /// // atan(tan(1)) - /// let abs_difference = (f.tan().atan() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn atan(self) -> Self; - /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). - /// - /// * `x = 0`, `y = 0`: `0` - /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` - /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` - /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let pi = f64::consts::PI; - /// // All angles from horizontal right (+x) - /// // 45 deg counter-clockwise - /// let x1 = 3.0; - /// let y1 = -3.0; - /// - /// // 135 deg clockwise - /// let x2 = -3.0; - /// let y2 = 3.0; - /// - /// let abs_difference_1 = (y1.atan2(x1) - (-pi/4.0)).abs(); - /// let abs_difference_2 = (y2.atan2(x2) - 3.0*pi/4.0).abs(); - /// - /// assert!(abs_difference_1 < 1e-10); - /// assert!(abs_difference_2 < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn atan2(self, other: Self) -> Self; - /// Simultaneously computes the sine and cosine of the number, `x`. Returns - /// `(sin(x), cos(x))`. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = f64::consts::PI/4.0; - /// let f = x.sin_cos(); - /// - /// let abs_difference_0 = (f.0 - x.sin()).abs(); - /// let abs_difference_1 = (f.1 - x.cos()).abs(); - /// - /// assert!(abs_difference_0 < 1e-10); - /// assert!(abs_difference_0 < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn sin_cos(self) -> (Self, Self); - - /// Returns `e^(self) - 1` in a way that is accurate even if the - /// number is close to zero. - /// - /// ``` - /// # #![feature(std_misc)] - /// use std::num::Float; - /// - /// let x = 7.0; - /// - /// // e^(ln(7)) - 1 - /// let abs_difference = (x.ln().exp_m1() - 6.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "may be renamed")] - fn exp_m1(self) -> Self; - /// Returns `ln(1+n)` (natural logarithm) more accurately than if - /// the operations were performed separately. - /// - /// ``` - /// # #![feature(std_misc, core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let x = f64::consts::E - 1.0; - /// - /// // ln(1 + (e - 1)) == ln(e) == 1 - /// let abs_difference = (x.ln_1p() - 1.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[unstable(feature = "std_misc", reason = "may be renamed")] - fn ln_1p(self) -> Self; - - /// Hyperbolic sine function. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0; - /// - /// let f = x.sinh(); - /// // Solving sinh() at 1 gives `(e^2-1)/(2e)` - /// let g = (e*e - 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn sinh(self) -> Self; - /// Hyperbolic cosine function. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0; - /// let f = x.cosh(); - /// // Solving cosh() at 1 gives this result - /// let g = (e*e + 1.0)/(2.0*e); - /// let abs_difference = (f - g).abs(); - /// - /// // Same result - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn cosh(self) -> Self; - /// Hyperbolic tangent function. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let x = 1.0; - /// - /// let f = x.tanh(); - /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))` - /// let g = (1.0 - e.powi(-2))/(1.0 + e.powi(-2)); - /// let abs_difference = (f - g).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn tanh(self) -> Self; - /// Inverse hyperbolic sine function. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 1.0; - /// let f = x.sinh().asinh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn asinh(self) -> Self; - /// Inverse hyperbolic cosine function. - /// - /// ``` - /// use std::num::Float; - /// - /// let x = 1.0; - /// let f = x.cosh().acosh(); - /// - /// let abs_difference = (f - x).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn acosh(self) -> Self; - /// Inverse hyperbolic tangent function. - /// - /// ``` - /// # #![feature(core)] - /// use std::num::Float; - /// use std::f64; - /// - /// let e = f64::consts::E; - /// let f = e.tanh().atanh(); - /// - /// let abs_difference = (f - e).abs(); - /// - /// assert!(abs_difference < 1.0e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn atanh(self) -> Self; -} +#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; +#[cfg(test)] use cmp::PartialEq; +#[cfg(test)] use marker::Copy; /// Helper function for testing numeric operations #[cfg(test)] pub fn test_num(ten: T, two: T) where - T: PartialEq + NumCast + T: PartialEq + Add + Sub + Mul + Div - + Rem + Debug + + Rem + fmt::Debug + Copy { - assert_eq!(ten.add(two), cast(12).unwrap()); - assert_eq!(ten.sub(two), cast(8).unwrap()); - assert_eq!(ten.mul(two), cast(20).unwrap()); - assert_eq!(ten.div(two), cast(5).unwrap()); - assert_eq!(ten.rem(two), cast(0).unwrap()); - assert_eq!(ten.add(two), ten + two); assert_eq!(ten.sub(two), ten - two); assert_eq!(ten.mul(two), ten * two); @@ -1150,6 +43,31 @@ pub fn test_num(ten: T, two: T) where assert_eq!(ten.rem(two), ten % two); } +/// An error which can be returned when parsing a float. +#[derive(Debug, Clone, PartialEq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseFloatError { inner: num::ParseFloatError } + +impl ::sys_common::FromInner for ParseFloatError { + fn from_inner(inner: num::ParseFloatError) -> ParseFloatError { + ParseFloatError { inner: inner } + } +} + +impl ParseFloatError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { + self.inner.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + #[cfg(test)] mod tests { use core::prelude::*; @@ -1165,432 +83,7 @@ mod tests { use u64; use usize; use string::ToString; - - macro_rules! test_cast_20 { - ($_20:expr) => ({ - let _20 = $_20; - - assert_eq!(20usize, _20.to_uint().unwrap()); - assert_eq!(20u8, _20.to_u8().unwrap()); - assert_eq!(20u16, _20.to_u16().unwrap()); - assert_eq!(20u32, _20.to_u32().unwrap()); - assert_eq!(20u64, _20.to_u64().unwrap()); - assert_eq!(20, _20.to_int().unwrap()); - assert_eq!(20i8, _20.to_i8().unwrap()); - assert_eq!(20i16, _20.to_i16().unwrap()); - assert_eq!(20i32, _20.to_i32().unwrap()); - assert_eq!(20i64, _20.to_i64().unwrap()); - assert_eq!(20f32, _20.to_f32().unwrap()); - assert_eq!(20f64, _20.to_f64().unwrap()); - - assert_eq!(_20, NumCast::from(20usize).unwrap()); - assert_eq!(_20, NumCast::from(20u8).unwrap()); - assert_eq!(_20, NumCast::from(20u16).unwrap()); - assert_eq!(_20, NumCast::from(20u32).unwrap()); - assert_eq!(_20, NumCast::from(20u64).unwrap()); - assert_eq!(_20, NumCast::from(20).unwrap()); - assert_eq!(_20, NumCast::from(20i8).unwrap()); - assert_eq!(_20, NumCast::from(20i16).unwrap()); - assert_eq!(_20, NumCast::from(20i32).unwrap()); - assert_eq!(_20, NumCast::from(20i64).unwrap()); - assert_eq!(_20, NumCast::from(20f32).unwrap()); - assert_eq!(_20, NumCast::from(20f64).unwrap()); - - assert_eq!(_20, cast(20usize).unwrap()); - assert_eq!(_20, cast(20u8).unwrap()); - assert_eq!(_20, cast(20u16).unwrap()); - assert_eq!(_20, cast(20u32).unwrap()); - assert_eq!(_20, cast(20u64).unwrap()); - assert_eq!(_20, cast(20).unwrap()); - assert_eq!(_20, cast(20i8).unwrap()); - assert_eq!(_20, cast(20i16).unwrap()); - assert_eq!(_20, cast(20i32).unwrap()); - assert_eq!(_20, cast(20i64).unwrap()); - assert_eq!(_20, cast(20f32).unwrap()); - assert_eq!(_20, cast(20f64).unwrap()); - }) - } - - #[test] fn test_u8_cast() { test_cast_20!(20u8) } - #[test] fn test_u16_cast() { test_cast_20!(20u16) } - #[test] fn test_u32_cast() { test_cast_20!(20u32) } - #[test] fn test_u64_cast() { test_cast_20!(20u64) } - #[test] fn test_uint_cast() { test_cast_20!(20usize) } - #[test] fn test_i8_cast() { test_cast_20!(20i8) } - #[test] fn test_i16_cast() { test_cast_20!(20i16) } - #[test] fn test_i32_cast() { test_cast_20!(20i32) } - #[test] fn test_i64_cast() { test_cast_20!(20i64) } - #[test] fn test_int_cast() { test_cast_20!(20) } - #[test] fn test_f32_cast() { test_cast_20!(20f32) } - #[test] fn test_f64_cast() { test_cast_20!(20f64) } - - #[test] - fn test_cast_range_int_min() { - assert_eq!(isize::MIN.to_int(), Some(isize::MIN as isize)); - assert_eq!(isize::MIN.to_i8(), None); - assert_eq!(isize::MIN.to_i16(), None); - // isize::MIN.to_i32() is word-size specific - assert_eq!(isize::MIN.to_i64(), Some(isize::MIN as i64)); - assert_eq!(isize::MIN.to_uint(), None); - assert_eq!(isize::MIN.to_u8(), None); - assert_eq!(isize::MIN.to_u16(), None); - assert_eq!(isize::MIN.to_u32(), None); - assert_eq!(isize::MIN.to_u64(), None); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(isize::MIN.to_i32(), Some(isize::MIN as i32)); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(isize::MIN.to_i32(), None); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_i8_min() { - assert_eq!(i8::MIN.to_int(), Some(i8::MIN as isize)); - assert_eq!(i8::MIN.to_i8(), Some(i8::MIN as i8)); - assert_eq!(i8::MIN.to_i16(), Some(i8::MIN as i16)); - assert_eq!(i8::MIN.to_i32(), Some(i8::MIN as i32)); - assert_eq!(i8::MIN.to_i64(), Some(i8::MIN as i64)); - assert_eq!(i8::MIN.to_uint(), None); - assert_eq!(i8::MIN.to_u8(), None); - assert_eq!(i8::MIN.to_u16(), None); - assert_eq!(i8::MIN.to_u32(), None); - assert_eq!(i8::MIN.to_u64(), None); - } - - #[test] - fn test_cast_range_i16_min() { - assert_eq!(i16::MIN.to_int(), Some(i16::MIN as isize)); - assert_eq!(i16::MIN.to_i8(), None); - assert_eq!(i16::MIN.to_i16(), Some(i16::MIN as i16)); - assert_eq!(i16::MIN.to_i32(), Some(i16::MIN as i32)); - assert_eq!(i16::MIN.to_i64(), Some(i16::MIN as i64)); - assert_eq!(i16::MIN.to_uint(), None); - assert_eq!(i16::MIN.to_u8(), None); - assert_eq!(i16::MIN.to_u16(), None); - assert_eq!(i16::MIN.to_u32(), None); - assert_eq!(i16::MIN.to_u64(), None); - } - - #[test] - fn test_cast_range_i32_min() { - assert_eq!(i32::MIN.to_int(), Some(i32::MIN as isize)); - assert_eq!(i32::MIN.to_i8(), None); - assert_eq!(i32::MIN.to_i16(), None); - assert_eq!(i32::MIN.to_i32(), Some(i32::MIN as i32)); - assert_eq!(i32::MIN.to_i64(), Some(i32::MIN as i64)); - assert_eq!(i32::MIN.to_uint(), None); - assert_eq!(i32::MIN.to_u8(), None); - assert_eq!(i32::MIN.to_u16(), None); - assert_eq!(i32::MIN.to_u32(), None); - assert_eq!(i32::MIN.to_u64(), None); - } - - #[test] - fn test_cast_range_i64_min() { - // i64::MIN.to_int() is word-size specific - assert_eq!(i64::MIN.to_i8(), None); - assert_eq!(i64::MIN.to_i16(), None); - assert_eq!(i64::MIN.to_i32(), None); - assert_eq!(i64::MIN.to_i64(), Some(i64::MIN as i64)); - assert_eq!(i64::MIN.to_uint(), None); - assert_eq!(i64::MIN.to_u8(), None); - assert_eq!(i64::MIN.to_u16(), None); - assert_eq!(i64::MIN.to_u32(), None); - assert_eq!(i64::MIN.to_u64(), None); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(i64::MIN.to_int(), None); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(i64::MIN.to_int(), Some(i64::MIN as isize)); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_int_max() { - assert_eq!(isize::MAX.to_int(), Some(isize::MAX as isize)); - assert_eq!(isize::MAX.to_i8(), None); - assert_eq!(isize::MAX.to_i16(), None); - // isize::MAX.to_i32() is word-size specific - assert_eq!(isize::MAX.to_i64(), Some(isize::MAX as i64)); - assert_eq!(isize::MAX.to_u8(), None); - assert_eq!(isize::MAX.to_u16(), None); - // isize::MAX.to_u32() is word-size specific - assert_eq!(isize::MAX.to_u64(), Some(isize::MAX as u64)); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(isize::MAX.to_i32(), Some(isize::MAX as i32)); - assert_eq!(isize::MAX.to_u32(), Some(isize::MAX as u32)); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(isize::MAX.to_i32(), None); - assert_eq!(isize::MAX.to_u32(), None); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_i8_max() { - assert_eq!(i8::MAX.to_int(), Some(i8::MAX as isize)); - assert_eq!(i8::MAX.to_i8(), Some(i8::MAX as i8)); - assert_eq!(i8::MAX.to_i16(), Some(i8::MAX as i16)); - assert_eq!(i8::MAX.to_i32(), Some(i8::MAX as i32)); - assert_eq!(i8::MAX.to_i64(), Some(i8::MAX as i64)); - assert_eq!(i8::MAX.to_uint(), Some(i8::MAX as usize)); - assert_eq!(i8::MAX.to_u8(), Some(i8::MAX as u8)); - assert_eq!(i8::MAX.to_u16(), Some(i8::MAX as u16)); - assert_eq!(i8::MAX.to_u32(), Some(i8::MAX as u32)); - assert_eq!(i8::MAX.to_u64(), Some(i8::MAX as u64)); - } - - #[test] - fn test_cast_range_i16_max() { - assert_eq!(i16::MAX.to_int(), Some(i16::MAX as isize)); - assert_eq!(i16::MAX.to_i8(), None); - assert_eq!(i16::MAX.to_i16(), Some(i16::MAX as i16)); - assert_eq!(i16::MAX.to_i32(), Some(i16::MAX as i32)); - assert_eq!(i16::MAX.to_i64(), Some(i16::MAX as i64)); - assert_eq!(i16::MAX.to_uint(), Some(i16::MAX as usize)); - assert_eq!(i16::MAX.to_u8(), None); - assert_eq!(i16::MAX.to_u16(), Some(i16::MAX as u16)); - assert_eq!(i16::MAX.to_u32(), Some(i16::MAX as u32)); - assert_eq!(i16::MAX.to_u64(), Some(i16::MAX as u64)); - } - - #[test] - fn test_cast_range_i32_max() { - assert_eq!(i32::MAX.to_int(), Some(i32::MAX as isize)); - assert_eq!(i32::MAX.to_i8(), None); - assert_eq!(i32::MAX.to_i16(), None); - assert_eq!(i32::MAX.to_i32(), Some(i32::MAX as i32)); - assert_eq!(i32::MAX.to_i64(), Some(i32::MAX as i64)); - assert_eq!(i32::MAX.to_uint(), Some(i32::MAX as usize)); - assert_eq!(i32::MAX.to_u8(), None); - assert_eq!(i32::MAX.to_u16(), None); - assert_eq!(i32::MAX.to_u32(), Some(i32::MAX as u32)); - assert_eq!(i32::MAX.to_u64(), Some(i32::MAX as u64)); - } - - #[test] - fn test_cast_range_i64_max() { - // i64::MAX.to_int() is word-size specific - assert_eq!(i64::MAX.to_i8(), None); - assert_eq!(i64::MAX.to_i16(), None); - assert_eq!(i64::MAX.to_i32(), None); - assert_eq!(i64::MAX.to_i64(), Some(i64::MAX as i64)); - // i64::MAX.to_uint() is word-size specific - assert_eq!(i64::MAX.to_u8(), None); - assert_eq!(i64::MAX.to_u16(), None); - assert_eq!(i64::MAX.to_u32(), None); - assert_eq!(i64::MAX.to_u64(), Some(i64::MAX as u64)); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(i64::MAX.to_int(), None); - assert_eq!(i64::MAX.to_uint(), None); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(i64::MAX.to_int(), Some(i64::MAX as isize)); - assert_eq!(i64::MAX.to_uint(), Some(i64::MAX as usize)); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_uint_min() { - assert_eq!(usize::MIN.to_int(), Some(usize::MIN as isize)); - assert_eq!(usize::MIN.to_i8(), Some(usize::MIN as i8)); - assert_eq!(usize::MIN.to_i16(), Some(usize::MIN as i16)); - assert_eq!(usize::MIN.to_i32(), Some(usize::MIN as i32)); - assert_eq!(usize::MIN.to_i64(), Some(usize::MIN as i64)); - assert_eq!(usize::MIN.to_uint(), Some(usize::MIN as usize)); - assert_eq!(usize::MIN.to_u8(), Some(usize::MIN as u8)); - assert_eq!(usize::MIN.to_u16(), Some(usize::MIN as u16)); - assert_eq!(usize::MIN.to_u32(), Some(usize::MIN as u32)); - assert_eq!(usize::MIN.to_u64(), Some(usize::MIN as u64)); - } - - #[test] - fn test_cast_range_u8_min() { - assert_eq!(u8::MIN.to_int(), Some(u8::MIN as isize)); - assert_eq!(u8::MIN.to_i8(), Some(u8::MIN as i8)); - assert_eq!(u8::MIN.to_i16(), Some(u8::MIN as i16)); - assert_eq!(u8::MIN.to_i32(), Some(u8::MIN as i32)); - assert_eq!(u8::MIN.to_i64(), Some(u8::MIN as i64)); - assert_eq!(u8::MIN.to_uint(), Some(u8::MIN as usize)); - assert_eq!(u8::MIN.to_u8(), Some(u8::MIN as u8)); - assert_eq!(u8::MIN.to_u16(), Some(u8::MIN as u16)); - assert_eq!(u8::MIN.to_u32(), Some(u8::MIN as u32)); - assert_eq!(u8::MIN.to_u64(), Some(u8::MIN as u64)); - } - - #[test] - fn test_cast_range_u16_min() { - assert_eq!(u16::MIN.to_int(), Some(u16::MIN as isize)); - assert_eq!(u16::MIN.to_i8(), Some(u16::MIN as i8)); - assert_eq!(u16::MIN.to_i16(), Some(u16::MIN as i16)); - assert_eq!(u16::MIN.to_i32(), Some(u16::MIN as i32)); - assert_eq!(u16::MIN.to_i64(), Some(u16::MIN as i64)); - assert_eq!(u16::MIN.to_uint(), Some(u16::MIN as usize)); - assert_eq!(u16::MIN.to_u8(), Some(u16::MIN as u8)); - assert_eq!(u16::MIN.to_u16(), Some(u16::MIN as u16)); - assert_eq!(u16::MIN.to_u32(), Some(u16::MIN as u32)); - assert_eq!(u16::MIN.to_u64(), Some(u16::MIN as u64)); - } - - #[test] - fn test_cast_range_u32_min() { - assert_eq!(u32::MIN.to_int(), Some(u32::MIN as isize)); - assert_eq!(u32::MIN.to_i8(), Some(u32::MIN as i8)); - assert_eq!(u32::MIN.to_i16(), Some(u32::MIN as i16)); - assert_eq!(u32::MIN.to_i32(), Some(u32::MIN as i32)); - assert_eq!(u32::MIN.to_i64(), Some(u32::MIN as i64)); - assert_eq!(u32::MIN.to_uint(), Some(u32::MIN as usize)); - assert_eq!(u32::MIN.to_u8(), Some(u32::MIN as u8)); - assert_eq!(u32::MIN.to_u16(), Some(u32::MIN as u16)); - assert_eq!(u32::MIN.to_u32(), Some(u32::MIN as u32)); - assert_eq!(u32::MIN.to_u64(), Some(u32::MIN as u64)); - } - - #[test] - fn test_cast_range_u64_min() { - assert_eq!(u64::MIN.to_int(), Some(u64::MIN as isize)); - assert_eq!(u64::MIN.to_i8(), Some(u64::MIN as i8)); - assert_eq!(u64::MIN.to_i16(), Some(u64::MIN as i16)); - assert_eq!(u64::MIN.to_i32(), Some(u64::MIN as i32)); - assert_eq!(u64::MIN.to_i64(), Some(u64::MIN as i64)); - assert_eq!(u64::MIN.to_uint(), Some(u64::MIN as usize)); - assert_eq!(u64::MIN.to_u8(), Some(u64::MIN as u8)); - assert_eq!(u64::MIN.to_u16(), Some(u64::MIN as u16)); - assert_eq!(u64::MIN.to_u32(), Some(u64::MIN as u32)); - assert_eq!(u64::MIN.to_u64(), Some(u64::MIN as u64)); - } - - #[test] - fn test_cast_range_uint_max() { - assert_eq!(usize::MAX.to_int(), None); - assert_eq!(usize::MAX.to_i8(), None); - assert_eq!(usize::MAX.to_i16(), None); - assert_eq!(usize::MAX.to_i32(), None); - // usize::MAX.to_i64() is word-size specific - assert_eq!(usize::MAX.to_u8(), None); - assert_eq!(usize::MAX.to_u16(), None); - // usize::MAX.to_u32() is word-size specific - assert_eq!(usize::MAX.to_u64(), Some(usize::MAX as u64)); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(usize::MAX.to_u32(), Some(usize::MAX as u32)); - assert_eq!(usize::MAX.to_i64(), Some(usize::MAX as i64)); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(usize::MAX.to_u32(), None); - assert_eq!(usize::MAX.to_i64(), None); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_u8_max() { - assert_eq!(u8::MAX.to_int(), Some(u8::MAX as isize)); - assert_eq!(u8::MAX.to_i8(), None); - assert_eq!(u8::MAX.to_i16(), Some(u8::MAX as i16)); - assert_eq!(u8::MAX.to_i32(), Some(u8::MAX as i32)); - assert_eq!(u8::MAX.to_i64(), Some(u8::MAX as i64)); - assert_eq!(u8::MAX.to_uint(), Some(u8::MAX as usize)); - assert_eq!(u8::MAX.to_u8(), Some(u8::MAX as u8)); - assert_eq!(u8::MAX.to_u16(), Some(u8::MAX as u16)); - assert_eq!(u8::MAX.to_u32(), Some(u8::MAX as u32)); - assert_eq!(u8::MAX.to_u64(), Some(u8::MAX as u64)); - } - - #[test] - fn test_cast_range_u16_max() { - assert_eq!(u16::MAX.to_int(), Some(u16::MAX as isize)); - assert_eq!(u16::MAX.to_i8(), None); - assert_eq!(u16::MAX.to_i16(), None); - assert_eq!(u16::MAX.to_i32(), Some(u16::MAX as i32)); - assert_eq!(u16::MAX.to_i64(), Some(u16::MAX as i64)); - assert_eq!(u16::MAX.to_uint(), Some(u16::MAX as usize)); - assert_eq!(u16::MAX.to_u8(), None); - assert_eq!(u16::MAX.to_u16(), Some(u16::MAX as u16)); - assert_eq!(u16::MAX.to_u32(), Some(u16::MAX as u32)); - assert_eq!(u16::MAX.to_u64(), Some(u16::MAX as u64)); - } - - #[test] - fn test_cast_range_u32_max() { - // u32::MAX.to_int() is word-size specific - assert_eq!(u32::MAX.to_i8(), None); - assert_eq!(u32::MAX.to_i16(), None); - assert_eq!(u32::MAX.to_i32(), None); - assert_eq!(u32::MAX.to_i64(), Some(u32::MAX as i64)); - assert_eq!(u32::MAX.to_uint(), Some(u32::MAX as usize)); - assert_eq!(u32::MAX.to_u8(), None); - assert_eq!(u32::MAX.to_u16(), None); - assert_eq!(u32::MAX.to_u32(), Some(u32::MAX as u32)); - assert_eq!(u32::MAX.to_u64(), Some(u32::MAX as u64)); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(u32::MAX.to_int(), None); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(u32::MAX.to_int(), Some(u32::MAX as isize)); - } - - check_word_size(); - } - - #[test] - fn test_cast_range_u64_max() { - assert_eq!(u64::MAX.to_int(), None); - assert_eq!(u64::MAX.to_i8(), None); - assert_eq!(u64::MAX.to_i16(), None); - assert_eq!(u64::MAX.to_i32(), None); - assert_eq!(u64::MAX.to_i64(), None); - // u64::MAX.to_uint() is word-size specific - assert_eq!(u64::MAX.to_u8(), None); - assert_eq!(u64::MAX.to_u16(), None); - assert_eq!(u64::MAX.to_u32(), None); - assert_eq!(u64::MAX.to_u64(), Some(u64::MAX as u64)); - - #[cfg(target_pointer_width = "32")] - fn check_word_size() { - assert_eq!(u64::MAX.to_uint(), None); - } - - #[cfg(target_pointer_width = "64")] - fn check_word_size() { - assert_eq!(u64::MAX.to_uint(), Some(u64::MAX as usize)); - } - - check_word_size(); - } + use ops::Mul; #[test] fn test_saturating_add_uint() { @@ -1613,23 +106,23 @@ mod tests { #[test] fn test_saturating_add_int() { use isize::{MIN,MAX}; - assert_eq!(3.saturating_add(5), 8); - assert_eq!(3.saturating_add(MAX-1), MAX); + assert_eq!(3i32.saturating_add(5), 8); + assert_eq!(3isize.saturating_add(MAX-1), MAX); assert_eq!(MAX.saturating_add(MAX), MAX); assert_eq!((MAX-2).saturating_add(1), MAX-1); - assert_eq!(3.saturating_add(-5), -2); + assert_eq!(3i32.saturating_add(-5), -2); assert_eq!(MIN.saturating_add(-1), MIN); - assert_eq!((-2).saturating_add(-MAX), MIN); + assert_eq!((-2isize).saturating_add(-MAX), MIN); } #[test] fn test_saturating_sub_int() { use isize::{MIN,MAX}; - assert_eq!(3.saturating_sub(5), -2); + assert_eq!(3i32.saturating_sub(5), -2); assert_eq!(MIN.saturating_sub(1), MIN); - assert_eq!((-2).saturating_sub(MAX), MIN); - assert_eq!(3.saturating_sub(-5), 8); - assert_eq!(3.saturating_sub(-(MAX-1)), MAX); + assert_eq!((-2isize).saturating_sub(MAX), MIN); + assert_eq!(3i32.saturating_sub(-5), 8); + assert_eq!(3isize.saturating_sub(-(MAX-1)), MAX); assert_eq!(MAX.saturating_sub(-MAX), MAX); assert_eq!((MAX-2).saturating_sub(-1), MAX-1); } @@ -1733,56 +226,10 @@ mod tests { test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } - #[derive(PartialEq, Debug)] - struct Value { x: isize } - - impl ToPrimitive for Value { - fn to_i64(&self) -> Option { self.x.to_i64() } - fn to_u64(&self) -> Option { self.x.to_u64() } - } - - impl FromPrimitive for Value { - fn from_i64(n: i64) -> Option { Some(Value { x: n as isize }) } - fn from_u64(n: u64) -> Option { Some(Value { x: n as isize }) } - } - - #[test] - fn test_to_primitive() { - let value = Value { x: 5 }; - assert_eq!(value.to_int(), Some(5)); - assert_eq!(value.to_i8(), Some(5)); - assert_eq!(value.to_i16(), Some(5)); - assert_eq!(value.to_i32(), Some(5)); - assert_eq!(value.to_i64(), Some(5)); - assert_eq!(value.to_uint(), Some(5)); - assert_eq!(value.to_u8(), Some(5)); - assert_eq!(value.to_u16(), Some(5)); - assert_eq!(value.to_u32(), Some(5)); - assert_eq!(value.to_u64(), Some(5)); - assert_eq!(value.to_f32(), Some(5f32)); - assert_eq!(value.to_f64(), Some(5f64)); - } - - #[test] - fn test_from_primitive() { - assert_eq!(from_int(5), Some(Value { x: 5 })); - assert_eq!(from_i8(5), Some(Value { x: 5 })); - assert_eq!(from_i16(5), Some(Value { x: 5 })); - assert_eq!(from_i32(5), Some(Value { x: 5 })); - assert_eq!(from_i64(5), Some(Value { x: 5 })); - assert_eq!(from_uint(5), Some(Value { x: 5 })); - assert_eq!(from_u8(5), Some(Value { x: 5 })); - assert_eq!(from_u16(5), Some(Value { x: 5 })); - assert_eq!(from_u32(5), Some(Value { x: 5 })); - assert_eq!(from_u64(5), Some(Value { x: 5 })); - assert_eq!(from_f32(5f32), Some(Value { x: 5 })); - assert_eq!(from_f64(5f64), Some(Value { x: 5 })); - } - #[test] fn test_pow() { - fn naive_pow(base: T, exp: usize) -> T { - let one: T = Int::one(); + fn naive_pow + One + Copy>(base: T, exp: usize) -> T { + let one: T = T::one(); (0..exp).fold(one, |acc, _| acc * base) } macro_rules! assert_pow { @@ -1792,11 +239,11 @@ mod tests { assert_eq!(result, naive_pow($num, $exp)); }} } - assert_pow!((3, 0 ) => 1); - assert_pow!((5, 1 ) => 5); - assert_pow!((-4, 2 ) => 16); - assert_pow!((8, 3 ) => 512); - assert_pow!((2u64, 50) => 1125899906842624); + assert_pow!((3u32, 0 ) => 1); + assert_pow!((5u32, 1 ) => 5); + assert_pow!((-4i32, 2 ) => 16); + assert_pow!((8u32, 3 ) => 512); + assert_pow!((2u64, 50) => 1125899906842624); } #[test] @@ -1871,12 +318,11 @@ mod tests { mod bench { extern crate test; use self::test::Bencher; - use num::Int; use prelude::v1::*; #[bench] fn bench_pow_function(b: &mut Bencher) { - let v = (0..1024).collect::>(); - b.iter(|| {v.iter().fold(0, |old, new| old.pow(*new as u32));}); + let v = (0..1024).collect::>(); + b.iter(|| {v.iter().fold(0u32, |old, new| old.pow(*new as u32));}); } } diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs deleted file mode 100644 index ea869ebae1..0000000000 --- a/src/libstd/num/strconv.rs +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2013-2014 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. -// -// ignore-lexer-test FIXME #15679 - -#![allow(missing_docs)] -#![allow(deprecated)] - -use self::ExponentFormat::*; -use self::SignificantDigits::*; -use self::SignFormat::*; - -use char; -use num::{self, Int, Float, ToPrimitive}; -use num::FpCategory as Fp; -use ops::FnMut; -use string::String; -use vec::Vec; - -/// A flag that specifies whether to use exponential (scientific) notation. -#[derive(Copy, Clone)] -pub enum ExponentFormat { - /// Do not use exponential notation. - ExpNone, - /// Use exponential notation with the exponent having a base of 10 and the - /// exponent sign being `e` or `E`. For example, 1000 would be printed - /// 1e3. - ExpDec, - /// Use exponential notation with the exponent having a base of 2 and the - /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3. - ExpBin, -} - -/// The number of digits used for emitting the fractional part of a number, if -/// any. -#[derive(Copy, Clone)] -pub enum SignificantDigits { - /// All calculable digits will be printed. - /// - /// Note that bignums or fractions may cause a surprisingly large number - /// of digits to be printed. - DigAll, - - /// At most the given number of digits will be printed, truncating any - /// trailing zeroes. - DigMax(usize), - - /// Precisely the given number of digits will be printed. - DigExact(usize) -} - -/// How to emit the sign of a number. -#[derive(Copy, Clone)] -pub enum SignFormat { - /// No sign will be printed. The exponent sign will also be emitted. - SignNone, - /// `-` will be printed for negative values, but no sign will be emitted - /// for positive numbers. - SignNeg, - /// `+` will be printed for positive values, and `-` will be printed for - /// negative values. - SignAll, -} - -/// Converts an integral number to its string representation as a byte vector. -/// This is meant to be a common base implementation for all integral string -/// conversion functions like `to_string()` or `to_str_radix()`. -/// -/// # Arguments -/// -/// - `num` - The number to convert. Accepts any number that -/// implements the numeric traits. -/// - `radix` - Base to use. Accepts only the values 2-36. -/// - `sign` - How to emit the sign. Options are: -/// - `SignNone`: No sign at all. Basically emits `abs(num)`. -/// - `SignNeg`: Only `-` on negative values. -/// - `SignAll`: Both `+` on positive, and `-` on negative numbers. -/// - `f` - a callback which will be invoked for each ascii character -/// which composes the string representation of this integer -/// -/// # Panics -/// -/// - Panics if `radix` < 2 or `radix` > 36. -fn int_to_str_bytes_common(num: T, radix: usize, sign: SignFormat, mut f: F) where - T: Int, - F: FnMut(u8), -{ - assert!(2 <= radix && radix <= 36); - - let _0: T = Int::zero(); - - let neg = num < _0; - let radix_gen: T = num::cast(radix).unwrap(); - - let mut deccum = num; - // This is just for integral types, the largest of which is a u64. The - // smallest base that we can have is 2, so the most number of digits we're - // ever going to have is 64 - let mut buf = [0; 64]; - let mut cur = 0; - - // Loop at least once to make sure at least a `0` gets emitted. - loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit_signed = deccum % radix_gen; - let current_digit = if current_digit_signed < _0 { - _0 - current_digit_signed - } else { - current_digit_signed - }; - buf[cur] = match current_digit.to_u8().unwrap() { - i @ 0...9 => b'0' + i, - i => b'a' + (i - 10), - }; - cur += 1; - - deccum = deccum / radix_gen; - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // Decide what sign to put in front - match sign { - SignNeg | SignAll if neg => { f(b'-'); } - SignAll => { f(b'+'); } - _ => () - } - - // We built the number in reverse order, so un-reverse it here - while cur > 0 { - cur -= 1; - f(buf[cur]); - } -} - -/// Converts a number to its string representation as a byte vector. -/// This is meant to be a common base implementation for all numeric string -/// conversion functions like `to_string()` or `to_str_radix()`. -/// -/// # Arguments -/// -/// - `num` - The number to convert. Accepts any number that -/// implements the numeric traits. -/// - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation -/// is used, then this base is only used for the significand. The exponent -/// itself always printed using a base of 10. -/// - `negative_zero` - Whether to treat the special value `-0` as -/// `-0` or as `+0`. -/// - `sign` - How to emit the sign. See `SignFormat`. -/// - `digits` - The amount of digits to use for emitting the fractional -/// part, if any. See `SignificantDigits`. -/// - `exp_format` - Whether or not to use the exponential (scientific) notation. -/// See `ExponentFormat`. -/// - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if -/// exponential notation is desired. -/// -/// # Return value -/// -/// A tuple containing the byte vector, and a boolean flag indicating -/// whether it represents a special value like `inf`, `-inf`, `NaN` or not. -/// It returns a tuple because there can be ambiguity between a special value -/// and a number representation at higher bases. -/// -/// # Panics -/// -/// - Panics if `radix` < 2 or `radix` > 36. -/// - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict -/// between digit and exponent sign `'e'`. -/// - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict -/// between digit and exponent sign `'p'`. -pub fn float_to_str_bytes_common( - num: T, radix: u32, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool - ) -> (Vec, bool) { - assert!(2 <= radix && radix <= 36); - match exp_format { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'p' as binary exponent", radix), - _ => () - } - - let _0: T = Float::zero(); - let _1: T = Float::one(); - - match num.classify() { - Fp::Nan => { return (b"NaN".to_vec(), true); } - Fp::Infinite if num > _0 => { - return match sign { - SignAll => (b"+inf".to_vec(), true), - _ => (b"inf".to_vec(), true) - }; - } - Fp::Infinite if num < _0 => { - return match sign { - SignNone => (b"inf".to_vec(), true), - _ => (b"-inf".to_vec(), true), - }; - } - _ => {} - } - - let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); - let mut buf = Vec::new(); - let radix_gen: T = num::cast(radix as isize).unwrap(); - - let (num, exp) = match exp_format { - ExpNone => (num, 0), - ExpDec | ExpBin => { - if num == _0 { - (num, 0) - } else { - let (exp, exp_base) = match exp_format { - ExpDec => (num.abs().log10().floor(), num::cast::(10.0f64).unwrap()), - ExpBin => (num.abs().log2().floor(), num::cast::(2.0f64).unwrap()), - ExpNone => unreachable!() - }; - - (num / exp_base.powf(exp), num::cast::(exp).unwrap()) - } - } - }; - - // First emit the non-fractional part, looping at least once to make - // sure at least a `0` gets emitted. - let mut deccum = num.trunc(); - loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit = (deccum % radix_gen).abs(); - - // Decrease the deccumulator one digit at a time - deccum = deccum / radix_gen; - deccum = deccum.trunc(); - - buf.push(char::from_digit(current_digit.to_isize().unwrap() as u32, radix) - .unwrap() as u8); - - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // If limited digits, calculate one digit more for rounding. - let (limit_digits, digit_count, exact) = match digits { - DigAll => (false, 0, false), - DigMax(count) => (true, count+1, false), - DigExact(count) => (true, count+1, true) - }; - - // Decide what sign to put in front - match sign { - SignNeg | SignAll if neg => { - buf.push(b'-'); - } - SignAll => { - buf.push(b'+'); - } - _ => () - } - - buf.reverse(); - - // Remember start of the fractional digits. - // Points one beyond end of buf if none get generated, - // or at the '.' otherwise. - let start_fractional_digits = buf.len(); - - // Now emit the fractional part, if any - deccum = num.fract(); - if deccum != _0 || (limit_digits && exact && digit_count > 0) { - buf.push(b'.'); - let mut dig = 0; - - // calculate new digits while - // - there is no limit and there are digits left - // - or there is a limit, it's not reached yet and - // - it's exact - // - or it's a maximum, and there are still digits left - while (!limit_digits && deccum != _0) - || (limit_digits && dig < digit_count && ( - exact - || (!exact && deccum != _0) - ) - ) { - // Shift first fractional digit into the integer part - deccum = deccum * radix_gen; - - // Calculate the absolute value of each digit. - // See note in first loop. - let current_digit = deccum.trunc().abs(); - - buf.push(char::from_digit( - current_digit.to_isize().unwrap() as u32, radix).unwrap() as u8); - - // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fract(); - dig += 1; - } - - // If digits are limited, and that limit has been reached, - // cut off the one extra digit, and depending on its value - // round the remaining ones. - if limit_digits && dig == digit_count { - let ascii2value = |chr: u8| { - (chr as char).to_digit(radix).unwrap() - }; - let value2ascii = |val: u32| { - char::from_digit(val, radix).unwrap() as u8 - }; - - let extra_digit = ascii2value(buf.pop().unwrap()); - if extra_digit >= radix / 2 { // -> need to round - let mut i: isize = buf.len() as isize - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i as usize] == b'-' - || buf[i as usize] == b'+' { - buf.insert((i + 1) as usize, value2ascii(1)); - break; - } - - // Skip the '.' - if buf[i as usize] == b'.' { i -= 1; continue; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i as usize]); - if current_digit < (radix - 1) { - buf[i as usize] = value2ascii(current_digit+1); - break; - } else { - buf[i as usize] = value2ascii(0); - i -= 1; - } - } - } - } - } - - // if number of digits is not exact, remove all trailing '0's up to - // and including the '.' - if !exact { - let buf_max_i = buf.len() - 1; - - // index to truncate from - let mut i = buf_max_i; - - // discover trailing zeros of fractional part - while i > start_fractional_digits && buf[i] == b'0' { - i -= 1; - } - - // Only attempt to truncate digits if buf has fractional digits - if i >= start_fractional_digits { - // If buf ends with '.', cut that too. - if buf[i] == b'.' { i -= 1 } - - // only resize buf if we actually remove digits - if i < buf_max_i { - buf = buf[.. (i + 1)].to_vec(); - } - } - } // If exact and trailing '.', just cut that - else { - let max_i = buf.len() - 1; - if buf[max_i] == b'.' { - buf = buf[.. max_i].to_vec(); - } - } - - match exp_format { - ExpNone => (), - _ => { - buf.push(match exp_format { - ExpDec if exp_upper => 'E', - ExpDec if !exp_upper => 'e', - ExpBin if exp_upper => 'P', - ExpBin if !exp_upper => 'p', - _ => unreachable!() - } as u8); - - int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c)); - } - } - - (buf, false) -} - -/// Converts a number to its string representation. This is a wrapper for -/// `to_str_bytes_common()`, for details see there. -#[inline] -pub fn float_to_str_common( - num: T, radix: u32, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool - ) -> (String, bool) { - let (bytes, special) = float_to_str_bytes_common(num, radix, - negative_zero, sign, digits, exp_format, exp_capital); - (String::from_utf8(bytes).unwrap(), special) -} - -// Some constants for from_str_bytes_common's input validation, -// they define minimum radix values for which the character is a valid digit. -const DIGIT_P_RADIX: u32 = ('p' as u32) - ('a' as u32) + 11; -const DIGIT_E_RADIX: u32 = ('e' as u32) - ('a' as u32) + 11; - -#[cfg(test)] -mod tests { - use core::num::wrapping::WrappingOps; - use string::ToString; - - #[test] - fn test_int_to_str_overflow() { - let mut i8_val: i8 = 127; - assert_eq!(i8_val.to_string(), "127"); - - i8_val = i8_val.wrapping_add(1); - assert_eq!(i8_val.to_string(), "-128"); - - let mut i16_val: i16 = 32_767; - assert_eq!(i16_val.to_string(), "32767"); - - i16_val = i16_val.wrapping_add(1); - assert_eq!(i16_val.to_string(), "-32768"); - - let mut i32_val: i32 = 2_147_483_647; - assert_eq!(i32_val.to_string(), "2147483647"); - - i32_val = i32_val.wrapping_add(1); - assert_eq!(i32_val.to_string(), "-2147483648"); - - let mut i64_val: i64 = 9_223_372_036_854_775_807; - assert_eq!(i64_val.to_string(), "9223372036854775807"); - - i64_val = i64_val.wrapping_add(1); - assert_eq!(i64_val.to_string(), "-9223372036854775808"); - } -} - -#[cfg(test)] -mod bench { - #![allow(deprecated)] // rand - extern crate test; - - mod usize { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use std::fmt; - - #[inline] - fn to_string(x: usize, base: u8) { - format!("{}", fmt::radix(x, base)); - } - - #[bench] - fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 2); }) - } - - #[bench] - fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 8); }) - } - - #[bench] - fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 10); }) - } - - #[bench] - fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 16); }) - } - - #[bench] - fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 36); }) - } - } - - mod isize { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use std::fmt; - - #[inline] - fn to_string(x: isize, base: u8) { - format!("{}", fmt::radix(x, base)); - } - - #[bench] - fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 2); }) - } - - #[bench] - fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 8); }) - } - - #[bench] - fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 10); }) - } - - #[bench] - fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 16); }) - } - - #[bench] - fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 36); }) - } - } - - mod f64 { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use f64; - - #[bench] - fn float_to_string(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { f64::to_string(rng.gen()); }) - } - } -} diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index c9e6a8f66d..96b0ba1c77 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -12,12 +12,11 @@ #![doc(hidden)] #![allow(unsigned_negation)] -macro_rules! uint_module { ($T:ty) => ( +macro_rules! uint_module { ($T:ident) => ( #[cfg(test)] mod tests { use prelude::v1::*; - use num::FromStrRadix; fn from_str(t: &str) -> Option { ::str::FromStr::from_str(t).ok() @@ -38,15 +37,15 @@ mod tests { #[test] pub fn test_parse_bytes() { - assert_eq!(FromStrRadix::from_str_radix("123", 10), Ok(123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("1001", 2), Ok(9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 8), Ok(83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 16), Ok(291 as u16)); - assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Ok(65535 as u16)); - assert_eq!(FromStrRadix::from_str_radix("z", 36), Ok(35 as $T)); - - assert_eq!(FromStrRadix::from_str_radix("Z", 10).ok(), None::<$T>); - assert_eq!(FromStrRadix::from_str_radix("_", 2).ok(), None::<$T>); + assert_eq!($T::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq!($T::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq!($T::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq!(u16::from_str_radix("123", 16), Ok(291 as u16)); + assert_eq!(u16::from_str_radix("ffff", 16), Ok(65535 as u16)); + assert_eq!($T::from_str_radix("z", 36), Ok(35 as $T)); + + assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>); + assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>); } } diff --git a/src/libstd/old_io/buffered.rs b/src/libstd/old_io/buffered.rs deleted file mode 100644 index 68aa7e4770..0000000000 --- a/src/libstd/old_io/buffered.rs +++ /dev/null @@ -1,702 +0,0 @@ -// Copyright 2013 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. -// -// ignore-lexer-test FIXME #15883 - -//! Buffering wrappers for I/O traits - -use cmp; -use fmt; -use old_io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; -use iter::{Iterator, ExactSizeIterator, repeat}; -use ops::Drop; -use option::Option; -use option::Option::{Some, None}; -use result::Result::Ok; -use slice; -use vec::Vec; - -/// Wraps a Reader and buffers input from it -/// -/// It can be excessively inefficient to work directly with a `Reader`. For -/// example, every call to `read` on `TcpStream` results in a system call. A -/// `BufferedReader` performs large, infrequent reads on the underlying -/// `Reader` and maintains an in-memory buffer of the results. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let file = File::open(&Path::new("message.txt")); -/// let mut reader = BufferedReader::new(file); -/// -/// let mut buf = [0; 100]; -/// match reader.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("error reading: {}", e) -/// } -/// ``` -pub struct BufferedReader { - inner: R, - buf: Vec, - pos: usize, - cap: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedReader where R: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "BufferedReader {{ reader: {:?}, buffer: {}/{} }}", - self.inner, self.cap - self.pos, self.buf.len()) - } -} - -impl BufferedReader { - /// Creates a new `BufferedReader` with the specified buffer capacity - pub fn with_capacity(cap: usize, inner: R) -> BufferedReader { - BufferedReader { - inner: inner, - // We can't use the same trick here as we do for BufferedWriter, - // since this memory is visible to the inner Reader. - buf: repeat(0).take(cap).collect(), - pos: 0, - cap: 0, - } - } - - /// Creates a new `BufferedReader` with a default buffer capacity - pub fn new(inner: R) -> BufferedReader { - BufferedReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Gets a reference to the underlying reader. - pub fn get_ref<'a>(&self) -> &R { &self.inner } - - /// Gets a mutable reference to the underlying reader. - /// - /// # Warning - /// - /// It is inadvisable to directly read from the underlying reader. - pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - - /// Unwraps this `BufferedReader`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. - pub fn into_inner(self) -> R { self.inner } -} - -impl Buffer for BufferedReader { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { - if self.pos == self.cap { - self.cap = try!(self.inner.read(&mut self.buf)); - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos += amt; - assert!(self.pos <= self.cap); - } -} - -impl Reader for BufferedReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.pos == self.cap && buf.len() >= self.buf.len() { - return self.inner.read(buf); - } - let nread = { - let available = try!(self.fill_buf()); - let nread = cmp::min(available.len(), buf.len()); - slice::bytes::copy_memory(&available[..nread], buf); - nread - }; - self.pos += nread; - Ok(nread) - } -} - -/// Wraps a Writer and buffers output to it -/// -/// It can be excessively inefficient to work directly with a `Writer`. For -/// example, every call to `write` on `TcpStream` results in a system call. A -/// `BufferedWriter` keeps an in memory buffer of data and writes it to the -/// underlying `Writer` in large, infrequent batches. -/// -/// This writer will be flushed when it is dropped. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let file = File::create(&Path::new("message.txt")).unwrap(); -/// let mut writer = BufferedWriter::new(file); -/// -/// writer.write_str("hello, world").unwrap(); -/// writer.flush().unwrap(); -/// ``` -pub struct BufferedWriter { - inner: Option, - buf: Vec, - pos: usize -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "BufferedWriter {{ writer: {:?}, buffer: {}/{} }}", - self.inner.as_ref().unwrap(), self.pos, self.buf.len()) - } -} - -impl BufferedWriter { - /// Creates a new `BufferedWriter` with the specified buffer capacity - pub fn with_capacity(cap: usize, inner: W) -> BufferedWriter { - // It's *much* faster to create an uninitialized buffer than it is to - // fill everything in with 0. This buffer is entirely an implementation - // detail and is never exposed, so we're safe to not initialize - // everything up-front. This allows creation of BufferedWriter instances - // to be very cheap (large mallocs are not nearly as expensive as large - // callocs). - let mut buf = Vec::with_capacity(cap); - unsafe { buf.set_len(cap); } - BufferedWriter { - inner: Some(inner), - buf: buf, - pos: 0 - } - } - - /// Creates a new `BufferedWriter` with a default buffer capacity - pub fn new(inner: W) -> BufferedWriter { - BufferedWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - fn flush_buf(&mut self) -> IoResult<()> { - if self.pos != 0 { - let ret = self.inner.as_mut().unwrap().write_all(&self.buf[..self.pos]); - self.pos = 0; - ret - } else { - Ok(()) - } - } - - /// Gets a reference to the underlying writer. - pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } - - /// Gets a mutable reference to the underlying write. - /// - /// # Warning - /// - /// It is inadvisable to directly read from the underlying writer. - pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } - - /// Unwraps this `BufferedWriter`, returning the underlying writer. - /// - /// The buffer is flushed before returning the writer. - pub fn into_inner(mut self) -> W { - // FIXME(#12628): is panicking the right thing to do if flushing panicks? - self.flush_buf().unwrap(); - self.inner.take().unwrap() - } -} - -impl Writer for BufferedWriter { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - if self.pos + buf.len() > self.buf.len() { - try!(self.flush_buf()); - } - - if buf.len() > self.buf.len() { - self.inner.as_mut().unwrap().write_all(buf) - } else { - let dst = &mut self.buf[self.pos..]; - slice::bytes::copy_memory(buf, dst); - self.pos += buf.len(); - Ok(()) - } - } - - fn flush(&mut self) -> IoResult<()> { - self.flush_buf().and_then(|()| self.inner.as_mut().unwrap().flush()) - } -} - -#[unsafe_destructor] -impl Drop for BufferedWriter { - fn drop(&mut self) { - if self.inner.is_some() { - // dtors should not panic, so we ignore a panicked flush - let _ = self.flush_buf(); - } - } -} - -/// Wraps a Writer and buffers output to it, flushing whenever a newline (`0x0a`, -/// `'\n'`) is detected. -/// -/// This writer will be flushed when it is dropped. -pub struct LineBufferedWriter { - inner: BufferedWriter, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for LineBufferedWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "LineBufferedWriter {{ writer: {:?}, buffer: {}/{} }}", - self.inner.inner, self.inner.pos, self.inner.buf.len()) - } -} - -impl LineBufferedWriter { - /// Creates a new `LineBufferedWriter` - pub fn new(inner: W) -> LineBufferedWriter { - // Lines typically aren't that long, don't use a giant buffer - LineBufferedWriter { - inner: BufferedWriter::with_capacity(1024, inner) - } - } - - /// Gets a reference to the underlying writer. - /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() } - - /// Unwraps this `LineBufferedWriter`, returning the underlying writer. - /// - /// The internal buffer is flushed before returning the writer. - pub fn into_inner(self) -> W { self.inner.into_inner() } -} - -impl Writer for LineBufferedWriter { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - match buf.iter().rposition(|&b| b == b'\n') { - Some(i) => { - try!(self.inner.write_all(&buf[..i + 1])); - try!(self.inner.flush()); - try!(self.inner.write_all(&buf[i + 1..])); - Ok(()) - } - None => self.inner.write_all(buf), - } - } - - fn flush(&mut self) -> IoResult<()> { self.inner.flush() } -} - -struct InternalBufferedWriter(BufferedWriter); - -impl InternalBufferedWriter { - fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter { - let InternalBufferedWriter(ref mut w) = *self; - return w; - } -} - -impl Reader for InternalBufferedWriter { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.get_mut().inner.as_mut().unwrap().read(buf) - } -} - -/// Wraps a Stream and buffers input and output to and from it. -/// -/// It can be excessively inefficient to work directly with a `Stream`. For -/// example, every call to `read` or `write` on `TcpStream` results in a system -/// call. A `BufferedStream` keeps in memory buffers of data, making large, -/// infrequent calls to `read` and `write` on the underlying `Stream`. -/// -/// The output half will be flushed when this stream is dropped. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let file = File::open(&Path::new("message.txt")); -/// let mut stream = BufferedStream::new(file); -/// -/// stream.write_all("hello, world".as_bytes()); -/// stream.flush(); -/// -/// let mut buf = [0; 100]; -/// match stream.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("error reading: {}", e) -/// } -/// ``` -pub struct BufferedStream { - inner: BufferedReader> -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for BufferedStream where S: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let reader = &self.inner; - let writer = &self.inner.inner.0; - write!(fmt, "BufferedStream {{ stream: {:?}, write_buffer: {}/{}, read_buffer: {}/{} }}", - writer.inner, - writer.pos, writer.buf.len(), - reader.cap - reader.pos, reader.buf.len()) - } -} - -impl BufferedStream { - /// Creates a new buffered stream with explicitly listed capacities for the - /// reader/writer buffer. - pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) - -> BufferedStream { - let writer = BufferedWriter::with_capacity(writer_cap, inner); - let internal_writer = InternalBufferedWriter(writer); - let reader = BufferedReader::with_capacity(reader_cap, - internal_writer); - BufferedStream { inner: reader } - } - - /// Creates a new buffered stream with the default reader/writer buffer - /// capacities. - pub fn new(inner: S) -> BufferedStream { - BufferedStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, - inner) - } - - /// Gets a reference to the underlying stream. - pub fn get_ref(&self) -> &S { - let InternalBufferedWriter(ref w) = self.inner.inner; - w.get_ref() - } - - /// Gets a mutable reference to the underlying stream. - /// - /// # Warning - /// - /// It is inadvisable to read directly from or write directly to the - /// underlying stream. - pub fn get_mut(&mut self) -> &mut S { - let InternalBufferedWriter(ref mut w) = self.inner.inner; - w.get_mut() - } - - /// Unwraps this `BufferedStream`, returning the underlying stream. - /// - /// The internal buffer is flushed before returning the stream. Any leftover - /// data in the read buffer is lost. - pub fn into_inner(self) -> S { - let InternalBufferedWriter(w) = self.inner.inner; - w.into_inner() - } -} - -impl Buffer for BufferedStream { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { self.inner.fill_buf() } - fn consume(&mut self, amt: usize) { self.inner.consume(amt) } -} - -impl Reader for BufferedStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for BufferedStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.inner.get_mut().write_all(buf) - } - fn flush(&mut self) -> IoResult<()> { - self.inner.inner.get_mut().flush() - } -} - -#[cfg(test)] -mod test { - extern crate test; - use old_io::{self, Reader, Writer, Buffer, BufferPrelude}; - use prelude::v1::*; - use super::*; - use super::super::{IoResult, EndOfFile}; - use super::super::mem::MemReader; - use self::test::Bencher; - - /// A type, free to create, primarily intended for benchmarking creation of - /// wrappers that, just for construction, don't need a Reader/Writer that - /// does anything useful. Is equivalent to `/dev/null` in semantics. - #[derive(Clone,PartialEq,PartialOrd)] - pub struct NullStream; - - impl Reader for NullStream { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - impl Writer for NullStream { - fn write_all(&mut self, _: &[u8]) -> old_io::IoResult<()> { Ok(()) } - } - - /// A dummy reader intended at testing short-reads propagation. - pub struct ShortReader { - lengths: Vec, - } - - impl Reader for ShortReader { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - if self.lengths.is_empty() { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(self.lengths.remove(0)) - } - } - } - - #[test] - fn test_buffered_reader() { - let inner = MemReader::new(vec!(5, 6, 7, 0, 1, 2, 3, 4)); - let mut reader = BufferedReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(Ok(3), nread); - let b: &[_] = &[5, 6, 7]; - assert_eq!(buf, b); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(Ok(2), nread); - let b: &[_] = &[0, 1]; - assert_eq!(buf, b); - - let mut buf = [0]; - let nread = reader.read(&mut buf); - assert_eq!(Ok(1), nread); - let b: &[_] = &[2]; - assert_eq!(buf, b); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(Ok(1), nread); - let b: &[_] = &[3, 0, 0]; - assert_eq!(buf, b); - - let nread = reader.read(&mut buf); - assert_eq!(Ok(1), nread); - let b: &[_] = &[4, 0, 0]; - assert_eq!(buf, b); - - assert!(reader.read(&mut buf).is_err()); - } - - #[test] - fn test_buffered_writer() { - let inner = Vec::new(); - let mut writer = BufferedWriter::with_capacity(2, inner); - - writer.write_all(&[0, 1]).unwrap(); - let b: &[_] = &[]; - assert_eq!(&writer.get_ref()[..], b); - - writer.write_all(&[2]).unwrap(); - let b: &[_] = &[0, 1]; - assert_eq!(&writer.get_ref()[..], b); - - writer.write_all(&[3]).unwrap(); - assert_eq!(&writer.get_ref()[..], b); - - writer.flush().unwrap(); - let a: &[_] = &[0, 1, 2, 3]; - assert_eq!(a, &writer.get_ref()[..]); - - writer.write_all(&[4]).unwrap(); - writer.write_all(&[5]).unwrap(); - assert_eq!(a, &writer.get_ref()[..]); - - writer.write_all(&[6]).unwrap(); - let a: &[_] = &[0, 1, 2, 3, 4, 5]; - assert_eq!(a, &writer.get_ref()[..]); - - writer.write_all(&[7, 8]).unwrap(); - let a: &[_] = &[0, 1, 2, 3, 4, 5, 6]; - assert_eq!(a, &writer.get_ref()[..]); - - writer.write_all(&[9, 10, 11]).unwrap(); - let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - assert_eq!(a, &writer.get_ref()[..]); - - writer.flush().unwrap(); - assert_eq!(a, &writer.get_ref()[..]); - } - - #[test] - fn test_buffered_writer_inner_flushes() { - let mut w = BufferedWriter::with_capacity(3, Vec::new()); - w.write_all(&[0, 1]).unwrap(); - let a: &[_] = &[]; - assert_eq!(&w.get_ref()[..], a); - let w = w.into_inner(); - let a: &[_] = &[0, 1]; - assert_eq!(a, &w[..]); - } - - // This is just here to make sure that we don't infinite loop in the - // newtype struct autoderef weirdness - #[test] - fn test_buffered_stream() { - struct S; - - impl old_io::Writer for S { - fn write_all(&mut self, _: &[u8]) -> old_io::IoResult<()> { Ok(()) } - } - - impl old_io::Reader for S { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - let mut stream = BufferedStream::new(S); - let mut buf = []; - assert!(stream.read(&mut buf).is_err()); - stream.write_all(&buf).unwrap(); - stream.flush().unwrap(); - } - - #[test] - fn test_read_until() { - let inner = MemReader::new(vec!(0, 1, 2, 1, 0)); - let mut reader = BufferedReader::with_capacity(2, inner); - assert_eq!(reader.read_until(0), Ok(vec!(0))); - assert_eq!(reader.read_until(2), Ok(vec!(1, 2))); - assert_eq!(reader.read_until(1), Ok(vec!(1))); - assert_eq!(reader.read_until(8), Ok(vec!(0))); - assert!(reader.read_until(9).is_err()); - } - - #[test] - fn test_line_buffer() { - let mut writer = LineBufferedWriter::new(Vec::new()); - writer.write_all(&[0]).unwrap(); - let b: &[_] = &[]; - assert_eq!(&writer.get_ref()[..], b); - writer.write_all(&[1]).unwrap(); - assert_eq!(&writer.get_ref()[..], b); - writer.flush().unwrap(); - let b: &[_] = &[0, 1]; - assert_eq!(&writer.get_ref()[..], b); - writer.write_all(&[0, b'\n', 1, b'\n', 2]).unwrap(); - let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n']; - assert_eq!(&writer.get_ref()[..], b); - writer.flush().unwrap(); - let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2]; - assert_eq!(&writer.get_ref()[..], b); - writer.write_all(&[3, b'\n']).unwrap(); - let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_read_line() { - let in_buf = MemReader::new(b"a\nb\nc".to_vec()); - let mut reader = BufferedReader::with_capacity(2, in_buf); - assert_eq!(reader.read_line(), Ok("a\n".to_string())); - assert_eq!(reader.read_line(), Ok("b\n".to_string())); - assert_eq!(reader.read_line(), Ok("c".to_string())); - assert!(reader.read_line().is_err()); - } - - #[test] - fn test_lines() { - let in_buf = MemReader::new(b"a\nb\nc".to_vec()); - let mut reader = BufferedReader::with_capacity(2, in_buf); - let mut it = reader.lines(); - assert_eq!(it.next(), Some(Ok("a\n".to_string()))); - assert_eq!(it.next(), Some(Ok("b\n".to_string()))); - assert_eq!(it.next(), Some(Ok("c".to_string()))); - assert_eq!(it.next(), None); - } - - #[test] - fn test_short_reads() { - let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; - let mut reader = BufferedReader::new(inner); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf), Ok(0)); - assert_eq!(reader.read(&mut buf), Ok(1)); - assert_eq!(reader.read(&mut buf), Ok(2)); - assert_eq!(reader.read(&mut buf), Ok(0)); - assert_eq!(reader.read(&mut buf), Ok(1)); - assert_eq!(reader.read(&mut buf), Ok(0)); - assert!(reader.read(&mut buf).is_err()); - } - - #[test] - fn read_char_buffered() { - let buf = [195, 159]; - let mut reader = BufferedReader::with_capacity(1, &buf[..]); - assert_eq!(reader.read_char(), Ok('ß')); - } - - #[test] - fn test_chars() { - let buf = [195, 159, b'a']; - let mut reader = BufferedReader::with_capacity(1, &buf[..]); - let mut it = reader.chars(); - assert_eq!(it.next(), Some(Ok('ß'))); - assert_eq!(it.next(), Some(Ok('a'))); - assert_eq!(it.next(), None); - } - - #[test] - #[should_panic] - fn dont_panic_in_drop_on_panicked_flush() { - struct FailFlushWriter; - - impl Writer for FailFlushWriter { - fn write_all(&mut self, _buf: &[u8]) -> IoResult<()> { Ok(()) } - fn flush(&mut self) -> IoResult<()> { Err(old_io::standard_error(EndOfFile)) } - } - - let writer = FailFlushWriter; - let _writer = BufferedWriter::new(writer); - - // If writer panics *again* due to the flush error then the process will abort. - panic!(); - } - - #[bench] - fn bench_buffered_reader(b: &mut Bencher) { - b.iter(|| { - BufferedReader::new(NullStream) - }); - } - - #[bench] - fn bench_buffered_writer(b: &mut Bencher) { - b.iter(|| { - BufferedWriter::new(NullStream) - }); - } - - #[bench] - fn bench_buffered_stream(b: &mut Bencher) { - b.iter(|| { - BufferedStream::new(NullStream); - }); - } -} diff --git a/src/libstd/old_io/comm_adapters.rs b/src/libstd/old_io/comm_adapters.rs deleted file mode 100644 index 5ebf931e95..0000000000 --- a/src/libstd/old_io/comm_adapters.rs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2013 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 clone::Clone; -use cmp; -use sync::mpsc::{Sender, Receiver}; -use old_io; -use option::Option::{None, Some}; -use result::Result::{Ok, Err}; -use slice::bytes; -use super::{Buffer, Reader, Writer, IoResult}; -use vec::Vec; - -/// Allows reading from a rx. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::sync::mpsc::channel; -/// use std::old_io::*; -/// -/// let (tx, rx) = channel(); -/// # drop(tx); -/// let mut reader = ChanReader::new(rx); -/// -/// let mut buf = [0; 100]; -/// match reader.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("read error: {}", e), -/// } -/// ``` -pub struct ChanReader { - buf: Vec, // A buffer of bytes received but not consumed. - pos: usize, // How many of the buffered bytes have already be consumed. - rx: Receiver>, // The Receiver to pull data from. - closed: bool, // Whether the channel this Receiver connects to has been closed. -} - -impl ChanReader { - /// Wraps a `Port` in a `ChanReader` structure - pub fn new(rx: Receiver>) -> ChanReader { - ChanReader { - buf: Vec::new(), - pos: 0, - rx: rx, - closed: false, - } - } -} - -impl Buffer for ChanReader { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { - if self.pos >= self.buf.len() { - self.pos = 0; - match self.rx.recv() { - Ok(bytes) => { - self.buf = bytes; - }, - Err(..) => { - self.closed = true; - self.buf = Vec::new(); - } - } - } - if self.closed { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(&self.buf[self.pos..]) - } - } - - fn consume(&mut self, amt: usize) { - self.pos += amt; - assert!(self.pos <= self.buf.len()); - } -} - -impl Reader for ChanReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let mut num_read = 0; - loop { - let count = match self.fill_buf().ok() { - Some(src) => { - let dst = &mut buf[num_read..]; - let count = cmp::min(src.len(), dst.len()); - bytes::copy_memory(&src[..count], dst); - count - }, - None => 0, - }; - self.consume(count); - num_read += count; - if num_read == buf.len() || self.closed { - break; - } - } - if self.closed && num_read == 0 { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(num_read) - } - } -} - -/// Allows writing to a tx. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, io)] -/// # #![allow(unused_must_use)] -/// use std::sync::mpsc::channel; -/// use std::old_io::*; -/// -/// let (tx, rx) = channel(); -/// # drop(rx); -/// let mut writer = ChanWriter::new(tx); -/// writer.write("hello, world".as_bytes()); -/// ``` -pub struct ChanWriter { - tx: Sender>, -} - -impl ChanWriter { - /// Wraps a channel in a `ChanWriter` structure - pub fn new(tx: Sender>) -> ChanWriter { - ChanWriter { tx: tx } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for ChanWriter { - fn clone(&self) -> ChanWriter { - ChanWriter { tx: self.tx.clone() } - } -} - -impl Writer for ChanWriter { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.tx.send(buf.to_vec()).map_err(|_| { - old_io::IoError { - kind: old_io::BrokenPipe, - desc: "Pipe closed", - detail: None - } - }) - } -} - - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use sync::mpsc::channel; - use super::*; - use old_io::{self, Reader, Writer, Buffer}; - use thread; - - #[test] - fn test_rx_reader() { - let (tx, rx) = channel(); - thread::spawn(move|| { - tx.send(vec![1, 2]).unwrap(); - tx.send(vec![]).unwrap(); - tx.send(vec![3, 4]).unwrap(); - tx.send(vec![5, 6]).unwrap(); - tx.send(vec![7, 8]).unwrap(); - }); - - let mut reader = ChanReader::new(rx); - let mut buf = [0; 3]; - - assert_eq!(Ok(0), reader.read(&mut [])); - - assert_eq!(Ok(3), reader.read(&mut buf)); - let a: &[u8] = &[1,2,3]; - assert_eq!(a, buf); - - assert_eq!(Ok(3), reader.read(&mut buf)); - let a: &[u8] = &[4,5,6]; - assert_eq!(a, buf); - - assert_eq!(Ok(2), reader.read(&mut buf)); - let a: &[u8] = &[7,8,6]; - assert_eq!(a, buf); - - match reader.read(&mut buf) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - assert_eq!(a, buf); - - // Ensure it continues to panic in the same way. - match reader.read(&mut buf) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - assert_eq!(a, buf); - } - - #[test] - fn test_rx_buffer() { - let (tx, rx) = channel(); - thread::spawn(move|| { - tx.send(b"he".to_vec()).unwrap(); - tx.send(b"llo wo".to_vec()).unwrap(); - tx.send(b"".to_vec()).unwrap(); - tx.send(b"rld\nhow ".to_vec()).unwrap(); - tx.send(b"are you?".to_vec()).unwrap(); - tx.send(b"".to_vec()).unwrap(); - }); - - let mut reader = ChanReader::new(rx); - - assert_eq!(Ok("hello world\n".to_string()), reader.read_line()); - assert_eq!(Ok("how are you?".to_string()), reader.read_line()); - match reader.read_line() { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - } - - #[test] - fn test_chan_writer() { - let (tx, rx) = channel(); - let mut writer = ChanWriter::new(tx); - writer.write_be_u32(42).unwrap(); - - let wanted = vec![0, 0, 0, 42]; - let got = thread::scoped(move|| { rx.recv().unwrap() }).join(); - assert_eq!(wanted, got); - - match writer.write_u8(1) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::BrokenPipe), - } - } -} diff --git a/src/libstd/old_io/extensions.rs b/src/libstd/old_io/extensions.rs deleted file mode 100644 index 73973d0db2..0000000000 --- a/src/libstd/old_io/extensions.rs +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright 2013-2014 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. - -//! Utility mixins that apply to all Readers and Writers - -#![allow(missing_docs)] -#![unstable(feature = "old_io")] -#![deprecated(since = "1.0.0", - reason = "functionality will be removed with no immediate \ - replacement")] - -// FIXME: Not sure how this should be structured -// FIXME: Iteration should probably be considered separately - -use old_io::{IoError, IoResult, Reader}; -use old_io; -use iter::Iterator; -use num::Int; -use ops::FnOnce; -use option::Option; -use option::Option::{Some, None}; -use result::Result::{Ok, Err}; - -/// An iterator that reads a single byte on each iteration, -/// until `.read_byte()` returns `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Bytes` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Bytes<'r, T:'r> { - reader: &'r mut T, -} - -impl<'r, R: Reader> Bytes<'r, R> { - /// Constructs a new byte iterator from the given Reader instance. - pub fn new(r: &'r mut R) -> Bytes<'r, R> { - Bytes { - reader: r, - } - } -} - -impl<'r, R: Reader> Iterator for Bytes<'r, R> { - type Item = IoResult; - - #[inline] - fn next(&mut self) -> Option> { - match self.reader.read_byte() { - Ok(x) => Some(Ok(x)), - Err(IoError { kind: old_io::EndOfFile, .. }) => None, - Err(e) => Some(Err(e)) - } - } -} - -/// Converts an 8-bit to 64-bit unsigned value to a little-endian byte -/// representation of the given size. If the size is not big enough to -/// represent the value, then the high-order bytes are truncated. -/// -/// Arguments: -/// -/// * `n`: The value to convert. -/// * `size`: The size of the value, in bytes. This must be 8 or less, or task -/// panic occurs. If this is less than 8, then a value of that -/// many bytes is produced. For example, if `size` is 4, then a -/// 32-bit byte representation is produced. -/// * `f`: A callback that receives the value. -/// -/// This function returns the value returned by the callback, for convenience. -pub fn u64_to_le_bytes(n: u64, size: usize, f: F) -> T where - F: FnOnce(&[u8]) -> T, -{ - use mem::transmute; - - // LLVM fails to properly optimize this when using shifts instead of the to_le* intrinsics - assert!(size <= 8); - match size { - 1 => f(&[n as u8]), - 2 => f(unsafe { & transmute::<_, [u8; 2]>((n as u16).to_le()) }), - 4 => f(unsafe { & transmute::<_, [u8; 4]>((n as u32).to_le()) }), - 8 => f(unsafe { & transmute::<_, [u8; 8]>(n.to_le()) }), - _ => { - - let mut bytes = vec!(); - let mut i = size; - let mut n = n; - while i > 0 { - bytes.push((n & 255) as u8); - n >>= 8; - i -= 1; - } - f(&bytes) - } - } -} - -/// Converts an 8-bit to 64-bit unsigned value to a big-endian byte -/// representation of the given size. If the size is not big enough to -/// represent the value, then the high-order bytes are truncated. -/// -/// Arguments: -/// -/// * `n`: The value to convert. -/// * `size`: The size of the value, in bytes. This must be 8 or less, or task -/// panic occurs. If this is less than 8, then a value of that -/// many bytes is produced. For example, if `size` is 4, then a -/// 32-bit byte representation is produced. -/// * `f`: A callback that receives the value. -/// -/// This function returns the value returned by the callback, for convenience. -pub fn u64_to_be_bytes(n: u64, size: usize, f: F) -> T where - F: FnOnce(&[u8]) -> T, -{ - use mem::transmute; - - // LLVM fails to properly optimize this when using shifts instead of the to_be* intrinsics - assert!(size <= 8); - match size { - 1 => f(&[n as u8]), - 2 => f(unsafe { & transmute::<_, [u8; 2]>((n as u16).to_be()) }), - 4 => f(unsafe { & transmute::<_, [u8; 4]>((n as u32).to_be()) }), - 8 => f(unsafe { & transmute::<_, [u8; 8]>(n.to_be()) }), - _ => { - let mut bytes = vec!(); - let mut i = size; - while i > 0 { - let shift = (i - 1) * 8; - bytes.push((n >> shift) as u8); - i -= 1; - } - f(&bytes) - } - } -} - -/// Extracts an 8-bit to 64-bit unsigned big-endian value from the given byte -/// buffer and returns it as a 64-bit value. -/// -/// Arguments: -/// -/// * `data`: The buffer in which to extract the value. -/// * `start`: The offset at which to extract the value. -/// * `size`: The size of the value in bytes to extract. This must be 8 or -/// less, or task panic occurs. If this is less than 8, then only -/// that many bytes are parsed. For example, if `size` is 4, then a -/// 32-bit value is parsed. -pub fn u64_from_be_bytes(data: &[u8], start: usize, size: usize) -> u64 { - use ptr::{copy_nonoverlapping}; - - assert!(size <= 8); - - if data.len() - start < size { - panic!("index out of bounds"); - } - - let mut buf = [0; 8]; - unsafe { - let ptr = data.as_ptr().offset(start as isize); - let out = buf.as_mut_ptr(); - copy_nonoverlapping(ptr, out.offset((8 - size) as isize), size); - (*(out as *const u64)).to_be() - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - use old_io::{self, Reader, Writer}; - use old_io::{MemReader, BytesReader}; - - struct InitialZeroByteReader { - count: isize, - } - - impl Reader for InitialZeroByteReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - if self.count == 0 { - self.count = 1; - Ok(0) - } else { - buf[0] = 10; - Ok(1) - } - } - } - - struct EofReader; - - impl Reader for EofReader { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - struct ErroringReader; - - impl Reader for ErroringReader { - fn read(&mut self, _: &mut [u8]) -> old_io::IoResult { - Err(old_io::standard_error(old_io::InvalidInput)) - } - } - - struct PartialReader { - count: isize, - } - - impl Reader for PartialReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - if self.count == 0 { - self.count = 1; - buf[0] = 10; - buf[1] = 11; - Ok(2) - } else { - buf[0] = 12; - buf[1] = 13; - Ok(2) - } - } - } - - struct ErroringLaterReader { - count: isize, - } - - impl Reader for ErroringLaterReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - if self.count == 0 { - self.count = 1; - buf[0] = 10; - Ok(1) - } else { - Err(old_io::standard_error(old_io::InvalidInput)) - } - } - } - - struct ThreeChunkReader { - count: isize, - } - - impl Reader for ThreeChunkReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - if self.count == 0 { - self.count = 1; - buf[0] = 10; - buf[1] = 11; - Ok(2) - } else if self.count == 1 { - self.count = 2; - buf[0] = 12; - buf[1] = 13; - Ok(2) - } else { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - } - - #[test] - fn read_byte() { - let mut reader = MemReader::new(vec!(10)); - let byte = reader.read_byte(); - assert!(byte == Ok(10)); - } - - #[test] - fn read_byte_0_bytes() { - let mut reader = InitialZeroByteReader { - count: 0, - }; - let byte = reader.read_byte(); - assert!(byte == Ok(10)); - } - - #[test] - fn read_byte_eof() { - let mut reader = EofReader; - let byte = reader.read_byte(); - assert!(byte.is_err()); - } - - #[test] - fn read_byte_error() { - let mut reader = ErroringReader; - let byte = reader.read_byte(); - assert!(byte.is_err()); - } - - #[test] - fn bytes_0_bytes() { - let mut reader = InitialZeroByteReader { - count: 0, - }; - let byte = reader.bytes().next(); - assert!(byte == Some(Ok(10))); - } - - #[test] - fn bytes_eof() { - let mut reader = EofReader; - let byte = reader.bytes().next(); - assert!(byte.is_none()); - } - - #[test] - fn bytes_error() { - let mut reader = ErroringReader; - let mut it = reader.bytes(); - let byte = it.next(); - assert!(byte.unwrap().is_err()); - } - - #[test] - fn read_bytes() { - let mut reader = MemReader::new(vec!(10, 11, 12, 13)); - let bytes = reader.read_exact(4).unwrap(); - assert_eq!(bytes, [10, 11, 12, 13]); - } - - #[test] - fn read_bytes_partial() { - let mut reader = PartialReader { - count: 0, - }; - let bytes = reader.read_exact(4).unwrap(); - assert_eq!(bytes, [10, 11, 12, 13]); - } - - #[test] - fn read_bytes_eof() { - let mut reader = MemReader::new(vec!(10, 11)); - assert!(reader.read_exact(4).is_err()); - } - - #[test] - fn push_at_least() { - let mut reader = MemReader::new(vec![10, 11, 12, 13]); - let mut buf = vec![8, 9]; - assert!(reader.push_at_least(4, 4, &mut buf).is_ok()); - assert_eq!(buf, [8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_at_least_partial() { - let mut reader = PartialReader { - count: 0, - }; - let mut buf = vec![8, 9]; - assert!(reader.push_at_least(4, 4, &mut buf).is_ok()); - assert_eq!(buf, [8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_at_least_eof() { - let mut reader = MemReader::new(vec![10, 11]); - let mut buf = vec![8, 9]; - assert!(reader.push_at_least(4, 4, &mut buf).is_err()); - assert_eq!(buf, [8, 9, 10, 11]); - } - - #[test] - fn push_at_least_error() { - let mut reader = ErroringLaterReader { - count: 0, - }; - let mut buf = vec![8, 9]; - assert!(reader.push_at_least(4, 4, &mut buf).is_err()); - assert_eq!(buf, [8, 9, 10]); - } - - #[test] - fn read_to_end() { - let mut reader = ThreeChunkReader { - count: 0, - }; - let buf = reader.read_to_end().unwrap(); - assert_eq!(buf, [10, 11, 12, 13]); - } - - #[test] - #[should_panic] - fn read_to_end_error() { - let mut reader = ThreeChunkReader { - count: 0, - }; - let buf = reader.read_to_end().unwrap(); - assert_eq!(buf, [10, 11]); - } - - #[test] - fn test_read_write_le_mem() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX]; - - let mut writer = Vec::new(); - for i in &uints { - writer.write_le_u64(*i).unwrap(); - } - - let mut reader = MemReader::new(writer); - for i in &uints { - assert!(reader.read_le_u64().unwrap() == *i); - } - } - - - #[test] - fn test_read_write_be() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::MAX]; - - let mut writer = Vec::new(); - for i in &uints { - writer.write_be_u64(*i).unwrap(); - } - - let mut reader = MemReader::new(writer); - for i in &uints { - assert!(reader.read_be_u64().unwrap() == *i); - } - } - - #[test] - fn test_read_be_int_n() { - let ints = [::i32::MIN, -123456, -42, -5, 0, 1, ::i32::MAX]; - - let mut writer = Vec::new(); - for i in &ints { - writer.write_be_i32(*i).unwrap(); - } - - let mut reader = MemReader::new(writer); - for i in &ints { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert!(reader.read_be_int_n(4).unwrap() == *i as i64); - } - } - - #[test] - fn test_read_f32() { - //big-endian floating-point 8.1250 - let buf = vec![0x41, 0x02, 0x00, 0x00]; - - let mut writer = Vec::new(); - writer.write(&buf).unwrap(); - - let mut reader = MemReader::new(writer); - let f = reader.read_be_f32().unwrap(); - assert!(f == 8.1250); - } - - #[test] - fn test_read_write_f32() { - let f:f32 = 8.1250; - - let mut writer = Vec::new(); - writer.write_be_f32(f).unwrap(); - writer.write_le_f32(f).unwrap(); - - let mut reader = MemReader::new(writer); - assert!(reader.read_be_f32().unwrap() == 8.1250); - assert!(reader.read_le_f32().unwrap() == 8.1250); - } - - #[test] - fn test_u64_from_be_bytes() { - use super::u64_from_be_bytes; - - let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; - - // Aligned access - assert_eq!(u64_from_be_bytes(&buf, 0, 0), 0); - assert_eq!(u64_from_be_bytes(&buf, 0, 1), 0x01); - assert_eq!(u64_from_be_bytes(&buf, 0, 2), 0x0102); - assert_eq!(u64_from_be_bytes(&buf, 0, 3), 0x010203); - assert_eq!(u64_from_be_bytes(&buf, 0, 4), 0x01020304); - assert_eq!(u64_from_be_bytes(&buf, 0, 5), 0x0102030405); - assert_eq!(u64_from_be_bytes(&buf, 0, 6), 0x010203040506); - assert_eq!(u64_from_be_bytes(&buf, 0, 7), 0x01020304050607); - assert_eq!(u64_from_be_bytes(&buf, 0, 8), 0x0102030405060708); - - // Unaligned access - assert_eq!(u64_from_be_bytes(&buf, 1, 0), 0); - assert_eq!(u64_from_be_bytes(&buf, 1, 1), 0x02); - assert_eq!(u64_from_be_bytes(&buf, 1, 2), 0x0203); - assert_eq!(u64_from_be_bytes(&buf, 1, 3), 0x020304); - assert_eq!(u64_from_be_bytes(&buf, 1, 4), 0x02030405); - assert_eq!(u64_from_be_bytes(&buf, 1, 5), 0x0203040506); - assert_eq!(u64_from_be_bytes(&buf, 1, 6), 0x020304050607); - assert_eq!(u64_from_be_bytes(&buf, 1, 7), 0x02030405060708); - assert_eq!(u64_from_be_bytes(&buf, 1, 8), 0x0203040506070809); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - use prelude::v1::*; - use self::test::Bencher; - - // why is this a macro? wouldn't an inlined function work just as well? - macro_rules! u64_from_be_bytes_bench_impl { - ($b:expr, $size:expr, $stride:expr, $start_index:expr) => - ({ - use super::u64_from_be_bytes; - - let len = ($stride as u8).wrapping_mul(100).wrapping_add($start_index); - let data = (0..len).collect::>(); - let mut sum = 0; - $b.iter(|| { - let mut i = $start_index; - while i < data.len() { - sum += u64_from_be_bytes(&data, i, $size); - i += $stride; - } - }); - }) - } - - #[bench] - fn u64_from_be_bytes_4_aligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 4, 4, 0); - } - - #[bench] - fn u64_from_be_bytes_4_unaligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 4, 4, 1); - } - - #[bench] - fn u64_from_be_bytes_7_aligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 7, 8, 0); - } - - #[bench] - fn u64_from_be_bytes_7_unaligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 7, 8, 1); - } - - #[bench] - fn u64_from_be_bytes_8_aligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 8, 8, 0); - } - - #[bench] - fn u64_from_be_bytes_8_unaligned(b: &mut Bencher) { - u64_from_be_bytes_bench_impl!(b, 8, 8, 1); - } -} diff --git a/src/libstd/old_io/fs.rs b/src/libstd/old_io/fs.rs deleted file mode 100644 index 509daa46ef..0000000000 --- a/src/libstd/old_io/fs.rs +++ /dev/null @@ -1,1654 +0,0 @@ -// Copyright 2013-2014 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. -// -// ignore-lexer-test FIXME #15679 - -//! Synchronous File I/O -//! -//! This module provides a set of functions and traits for working -//! with regular files & directories on a filesystem. -//! -//! At the top-level of the module are a set of freestanding functions, associated -//! with various filesystem operations. They all operate on `Path` objects. -//! -//! All operations in this module, including those as part of `File` et al block -//! the task during execution. In the event of failure, all functions/methods -//! will return an `IoResult` type with an `Err` value. -//! -//! Also included in this module is an implementation block on the `Path` object -//! defined in `std::path::Path`. The impl adds useful methods about inspecting -//! the metadata of a file. This includes getting the `stat` information, -//! reading off particular bits of it, etc. -//! -//! # Examples -//! -//! ```rust -//! # #![feature(old_io, io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::fs::PathExtensions; -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("foo.txt"); -//! -//! // create the file, whether it exists or not -//! let mut file = File::create(&path); -//! file.write(b"foobar"); -//! # drop(file); -//! -//! // open the file in read-only mode -//! let mut file = File::open(&path); -//! file.read_to_end(); -//! -//! println!("{}", path.stat().unwrap().size); -//! # drop(file); -//! fs::unlink(&path); -//! ``` - -use clone::Clone; -use old_io::standard_error; -use old_io::{FilePermission, Write, Open, FileAccess, FileMode, FileType}; -use old_io::{IoResult, IoError, InvalidInput}; -use old_io::{FileStat, SeekStyle, Seek, Writer, Reader}; -use old_io::{Read, Truncate, ReadWrite, Append}; -use old_io::UpdateIoError; -use old_io; -use iter::{Iterator, Extend}; -use option::Option; -use option::Option::{Some, None}; -use old_path::{Path, GenericPath}; -use old_path; -use result::Result::{Err, Ok}; -use string::String; -use vec::Vec; - -use sys::fs as fs_imp; -use sys_common; - -/// Unconstrained file access type that exposes read and write operations -/// -/// Can be constructed via `File::open()`, `File::create()`, and -/// `File::open_mode()`. -/// -/// # Error -/// -/// This type will return errors as an `IoResult` if operations are -/// attempted against it for which its underlying file descriptor was not -/// configured at creation time, via the `FileAccess` parameter to -/// `File::open_mode()`. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::File")] -#[unstable(feature = "old_io")] -pub struct File { - fd: fs_imp::FileDesc, - path: Path, - last_nread: isize, -} - -impl sys_common::AsInner for File { - fn as_inner(&self) -> &fs_imp::FileDesc { - &self.fd - } -} - -#[deprecated(since = "1.0.0", reason = "replaced with std::fs")] -#[unstable(feature = "old_io")] -impl File { - /// Open a file at `path` in the mode specified by the `mode` and `access` - /// arguments - /// - /// # Examples - /// - /// ```rust,should_panic - /// # #![feature(old_io, old_path)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let p = Path::new("/some/file/path.txt"); - /// - /// let file = match File::open_mode(&p, Open, ReadWrite) { - /// Ok(f) => f, - /// Err(e) => panic!("file error: {}", e), - /// }; - /// // do some stuff with that file - /// - /// // the file will be closed at the end of this block - /// ``` - /// - /// `FileMode` and `FileAccess` provide information about the permissions - /// context in which a given stream is created. More information about them - /// can be found in `std::io`'s docs. If a file is opened with `Write` - /// or `ReadWrite` access, then it will be created if it does not already - /// exist. - /// - /// Note that, with this function, a `File` is returned regardless of the - /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a - /// `File` opened as `Read` will return an error at runtime). - /// - /// # Error - /// - /// This function will return an error under a number of different - /// circumstances, to include but not limited to: - /// - /// * Opening a file that does not exist with `Read` access. - /// * Attempting to open a file with a `FileAccess` that the user lacks - /// permissions for - /// * Filesystem-level errors (full disk, etc) - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::OpenOptions")] - #[unstable(feature = "old_io")] - pub fn open_mode(path: &Path, - mode: FileMode, - access: FileAccess) -> IoResult { - fs_imp::open(path, mode, access).and_then(|fd| { - // On *BSD systems, we can open a directory as a file and read from it: - // fd=open("/tmp", O_RDONLY); read(fd, buf, N); - // due to an old tradition before the introduction of opendir(3). - // We explicitly reject it because there are few use cases. - if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) && - try!(fd.fstat()).kind == FileType::Directory { - Err(IoError { - kind: InvalidInput, - desc: "is a directory", - detail: None - }) - } else { - Ok(File { - path: path.clone(), - fd: fd, - last_nread: -1 - }) - } - }).update_err("couldn't open path as file", |e| { - format!("{}; path={}; mode={}; access={}", e, path.display(), - mode_string(mode), access_string(access)) - }) - } - - /// Attempts to open a file in read-only mode. This function is equivalent to - /// `File::open_mode(path, Open, Read)`, and will raise all of the same - /// errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, old_path)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); - /// ``` - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::open")] - #[unstable(feature = "old_io")] - pub fn open(path: &Path) -> IoResult { - File::open_mode(path, Open, Read) - } - - /// Attempts to create a file in write-only mode. This function is - /// equivalent to `File::open_mode(path, Truncate, Write)`, and will - /// raise all of the same errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, old_path, io)] - /// # #![allow(unused_must_use)] - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(b"This is a sample file"); - /// # drop(f); - /// # ::std::old_io::fs::unlink(&Path::new("foo.txt")); - /// ``` - #[deprecated(since = "1.0.0", reason = "replaced with std::fs::File::create")] - #[unstable(feature = "old_io")] - pub fn create(path: &Path) -> IoResult { - File::open_mode(path, Truncate, Write) - .update_desc("couldn't create file") - } - - /// Returns the original path that was used to open this file. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn path<'a>(&'a self) -> &'a Path { - &self.path - } - - /// Synchronizes all modifications to this file to its permanent storage - /// device. This will flush any internal buffers necessary to perform this - /// operation. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn fsync(&mut self) -> IoResult<()> { - self.fd.fsync() - .update_err("couldn't fsync file", - |e| format!("{}; path={}", e, self.path.display())) - } - - /// This function is similar to `fsync`, except that it may not synchronize - /// file metadata to the filesystem. This is intended for use cases that - /// must synchronize content, but don't need the metadata on disk. The goal - /// of this method is to reduce disk operations. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn datasync(&mut self) -> IoResult<()> { - self.fd.datasync() - .update_err("couldn't datasync file", - |e| format!("{}; path={}", e, self.path.display())) - } - - /// Either truncates or extends the underlying file, updating the size of - /// this file to become `size`. This is equivalent to unix's `truncate` - /// function. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn truncate(&mut self, size: i64) -> IoResult<()> { - self.fd.truncate(size) - .update_err("couldn't truncate file", |e| - format!("{}; path={}; size={}", e, self.path.display(), size)) - } - - /// Returns true if the stream has reached the end of the file. - /// - /// If true, then this file will no longer continue to return data via - /// `read`. - /// - /// Note that the operating system will not return an `EOF` indicator - /// until you have attempted to read past the end of the file, so if - /// you've read _exactly_ the number of bytes in the file, this will - /// return `false`, not `true`. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn eof(&self) -> bool { - self.last_nread == 0 - } - - /// Queries information about the underlying file. - #[deprecated(since = "1.0.0", reason = "replaced with std::fs")] - #[unstable(feature = "old_io")] - pub fn stat(&self) -> IoResult { - self.fd.fstat() - .update_err("couldn't fstat file", |e| - format!("{}; path={}", e, self.path.display())) - } -} - -/// Unlink a file from the underlying filesystem. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/file/path.txt"); -/// fs::unlink(&p); -/// ``` -/// -/// Note that, just because an unlink call was successful, it is not -/// guaranteed that a file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal) -/// -/// # Error -/// -/// This function will return an error if `path` points to a directory, if the -/// user lacks permissions to remove the file, or if some other filesystem-level -/// error occurs. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_file")] -#[unstable(feature = "old_io")] -pub fn unlink(path: &Path) -> IoResult<()> { - fs_imp::unlink(path) - .update_err("couldn't unlink path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Given a path, query the file system to get information about a file, -/// directory, etc. This function will traverse symlinks to query -/// information about the destination file. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/file/path.txt"); -/// match fs::stat(&p) { -/// Ok(stat) => { /* ... */ } -/// Err(e) => { /* handle error */ } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks the requisite permissions -/// to perform a `stat` call on the given `path` or if there is no entry in the -/// filesystem at the provided path. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::metadata")] -#[unstable(feature = "old_io")] -pub fn stat(path: &Path) -> IoResult { - fs_imp::stat(path) - .update_err("couldn't stat path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Perform the same operation as the `stat` function, except that this -/// function does not traverse through symlinks. This will return -/// information about the symlink file instead of the file that it points -/// to. -/// -/// # Error -/// -/// See `stat` -#[unstable(feature = "old_fs")] -pub fn lstat(path: &Path) -> IoResult { - fs_imp::lstat(path) - .update_err("couldn't lstat path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Rename a file or directory to a new name. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::rename(&Path::new("foo"), &Path::new("bar")); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `from` doesn't exist, if -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::rename")] -#[unstable(feature = "old_io")] -pub fn rename(from: &Path, to: &Path) -> IoResult<()> { - fs_imp::rename(from, to) - .update_err("couldn't rename path", |e| - format!("{}; from={:?}; to={:?}", e, from.display(), to.display())) -} - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); -/// ``` -/// -/// # Error -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `from` path is not a file -/// * The `from` file does not exist -/// * The current process does not have the permission rights to access -/// `from` or write `to` -/// -/// Note that this copy is not atomic in that once the destination is -/// ensured to not exist, there is nothing preventing the destination from -/// being created and then destroyed by this operation. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::copy")] -#[unstable(feature = "old_io")] -pub fn copy(from: &Path, to: &Path) -> IoResult<()> { - fn update_err(result: IoResult, from: &Path, to: &Path) -> IoResult { - result.update_err("couldn't copy path", |e| { - format!("{}; from={:?}; to={:?}", e, from.display(), to.display()) - }) - } - - if !from.is_file() { - return update_err(Err(IoError { - kind: old_io::MismatchedFileTypeForOperation, - desc: "the source path is not an existing file", - detail: None - }), from, to) - } - - let mut reader = try!(File::open(from)); - let mut writer = try!(File::create(to)); - - try!(update_err(super::util::copy(&mut reader, &mut writer), from, to)); - - chmod(to, try!(update_err(from.stat(), from, to)).perm) -} - -/// Changes the permission mode bits found on a file or a directory. This -/// function takes a mask from the `io` module -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// fs::chmod(&Path::new("file.txt"), old_io::USER_FILE); -/// fs::chmod(&Path::new("file.txt"), old_io::USER_READ | old_io::USER_WRITE); -/// fs::chmod(&Path::new("dir"), old_io::USER_DIR); -/// fs::chmod(&Path::new("file.exe"), old_io::USER_EXEC); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to change the attributes of the file, or if -/// some other I/O error is encountered. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_permissions")] -#[unstable(feature = "old_io")] -pub fn chmod(path: &Path, mode: old_io::FilePermission) -> IoResult<()> { - fs_imp::chmod(path, mode.bits() as usize) - .update_err("couldn't chmod path", |e| - format!("{}; path={}; mode={:?}", e, path.display(), mode)) -} - -/// Change the user and group owners of a file at the specified path. -#[unstable(feature = "old_fs")] -pub fn chown(path: &Path, uid: isize, gid: isize) -> IoResult<()> { - fs_imp::chown(path, uid, gid) - .update_err("couldn't chown path", |e| - format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid)) -} - -/// Creates a new hard link on the filesystem. The `dst` path will be a -/// link pointing to the `src` path. Note that systems often require these -/// two paths to both be located on the same filesystem. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::hard_link")] -#[unstable(feature = "old_io")] -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - fs_imp::link(src, dst) - .update_err("couldn't link path", |e| - format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display())) -} - -/// Creates a new symbolic link on the filesystem. The `dst` path will be a -/// symlink pointing to the `src` path. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::soft_link")] -#[unstable(feature = "old_io")] -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - fs_imp::symlink(src, dst) - .update_err("couldn't symlink path", |e| - format!("{}; src={:?}; dest={:?}", e, src.display(), dst.display())) -} - -/// Reads a symlink, returning the file that the symlink points to. -/// -/// # Error -/// -/// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file that is not a symlink. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_link")] -#[unstable(feature = "old_io")] -pub fn readlink(path: &Path) -> IoResult { - fs_imp::readlink(path) - .update_err("couldn't resolve symlink for path", |e| - format!("{}; path={}", e, path.display())) -} - -/// Create a new, empty directory at the provided path -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path, old_fs)] -/// # #![allow(unused_must_use)] -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/dir"); -/// fs::mkdir(&p, old_io::USER_RWX); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to make a -/// new directory at the provided `path`, or if the directory already exists. -#[unstable(feature = "old_fs")] -pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { - fs_imp::mkdir(path, mode.bits() as usize) - .update_err("couldn't create directory", |e| - format!("{}; path={}; mode={}", e, path.display(), mode)) -} - -/// Remove an existing, empty directory -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// let p = Path::new("/some/dir"); -/// fs::rmdir(&p); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to remove -/// the directory at the provided `path`, or if the directory isn't empty. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir")] -#[unstable(feature = "old_io")] -pub fn rmdir(path: &Path) -> IoResult<()> { - fs_imp::rmdir(path) - .update_err("couldn't remove directory", |e| - format!("{}; path={}", e, path.display())) -} - -/// Retrieve a vector containing all entries within a provided directory -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, old_path)] -/// use std::old_io::fs::PathExtensions; -/// use std::old_io; -/// use std::old_io::*; -/// use std::old_path::Path; -/// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: &mut F) -> old_io::IoResult<()> where -/// F: FnMut(&Path), -/// { -/// if dir.is_dir() { -/// let contents = try!(fs::readdir(dir)); -/// for entry in contents.iter() { -/// if entry.is_dir() { -/// try!(visit_dirs(entry, cb)); -/// } else { -/// (*cb)(entry); -/// } -/// } -/// Ok(()) -/// } else { -/// Err(old_io::standard_error(old_io::InvalidInput)) -/// } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to view the contents or if the `path` points -/// at a non-directory file -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::read_dir")] -#[unstable(feature = "old_io")] -pub fn readdir(path: &Path) -> IoResult> { - fs_imp::readdir(path) - .update_err("couldn't read directory", - |e| format!("{}; path={}", e, path.display())) -} - -/// Returns an iterator that will recursively walk the directory structure -/// rooted at `path`. The path given will not be iterated over, and this will -/// perform iteration in some top-down order. The contents of unreadable -/// subdirectories are ignored. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::walk_dir")] -#[unstable(feature = "old_io")] -pub fn walk_dir(path: &Path) -> IoResult { - Ok(Directories { - stack: try!(readdir(path).update_err("couldn't walk directory", - |e| format!("{}; path={}", e, path.display()))) - }) -} - -/// An iterator that walks over a directory -#[derive(Clone)] -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::ReadDir")] -#[unstable(feature = "old_io")] -pub struct Directories { - stack: Vec, -} - -impl Iterator for Directories { - type Item = Path; - - fn next(&mut self) -> Option { - match self.stack.pop() { - Some(path) => { - if path.is_dir() { - match readdir(&path) { - Ok(dirs) => { self.stack.extend(dirs.into_iter()); } - Err(..) => {} - } - } - Some(path) - } - None => None - } - } -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// # Error -/// -/// See `fs::mkdir`. -#[unstable(feature = "old_fs")] -pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { - // tjc: if directory exists but with different permissions, - // should we return false? - if path.is_dir() { - return Ok(()) - } - - let comps = path.components(); - let mut curpath = path.root_path().unwrap_or(Path::new(".")); - - for c in comps { - curpath.push(c); - - let result = mkdir(&curpath, mode) - .update_err("couldn't recursively mkdir", - |e| format!("{}; path={}", e, path.display())); - - match result { - Err(mkdir_err) => { - // already exists ? - if try!(stat(&curpath)).kind != FileType::Directory { - return Err(mkdir_err); - } - } - Ok(()) => () - } - } - - Ok(()) -} - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// # Error -/// -/// See `file::unlink` and `fs::readdir` -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::remove_dir_all")] -#[unstable(feature = "old_io")] -pub fn rmdir_recursive(path: &Path) -> IoResult<()> { - let mut rm_stack = Vec::new(); - rm_stack.push(path.clone()); - - fn rmdir_failed(err: &IoError, path: &Path) -> String { - format!("rmdir_recursive failed; path={}; cause={}", - path.display(), err) - } - - fn update_err(err: IoResult, path: &Path) -> IoResult { - err.update_err("couldn't recursively rmdir", - |e| rmdir_failed(e, path)) - } - - while !rm_stack.is_empty() { - let children = try!(readdir(rm_stack.last().unwrap()) - .update_detail(|e| rmdir_failed(e, path))); - - let mut has_child_dir = false; - - // delete all regular files in the way and push subdirs - // on the stack - for child in children { - // FIXME(#12795) we should use lstat in all cases - let child_type = match cfg!(windows) { - true => try!(update_err(stat(&child), path)), - false => try!(update_err(lstat(&child), path)) - }; - - if child_type.kind == FileType::Directory { - rm_stack.push(child); - has_child_dir = true; - } else { - // we can carry on safely if the file is already gone - // (eg: deleted by someone else since readdir) - match update_err(unlink(&child), path) { - Ok(()) => (), - Err(ref e) if e.kind == old_io::FileNotFound => (), - Err(e) => return Err(e) - } - } - } - - // if no subdir was found, let's pop and delete - if !has_child_dir { - let result = update_err(rmdir(&rm_stack.pop().unwrap()), path); - match result { - Ok(()) => (), - Err(ref e) if e.kind == old_io::FileNotFound => (), - Err(e) => return Err(e) - } - } - } - - Ok(()) -} - -/// Changes the timestamps for a file's last modification and access time. -/// The file at the path specified will have its last access time set to -/// `atime` and its modification time set to `mtime`. The times specified should -/// be in milliseconds. -// FIXME(#10301) these arguments should not be u64 -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::set_file_times")] -#[unstable(feature = "old_io")] -pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { - fs_imp::utime(path, atime, mtime) - .update_err("couldn't change_file_times", |e| - format!("{}; path={}", e, path.display())) -} - -impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - fn update_err(result: IoResult, file: &File) -> IoResult { - result.update_err("couldn't read file", - |e| format!("{}; path={}", - e, file.path.display())) - } - - let result = update_err(self.fd.read(buf), self); - - match result { - Ok(read) => { - self.last_nread = read as isize; - match read { - 0 => update_err(Err(standard_error(old_io::EndOfFile)), self), - _ => Ok(read as usize) - } - }, - Err(e) => Err(e) - } - } -} - -impl Writer for File { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.fd.write(buf) - .update_err("couldn't write to file", - |e| format!("{}; path={}", e, self.path.display())) - } -} - -impl Seek for File { - fn tell(&self) -> IoResult { - self.fd.tell() - .update_err("couldn't retrieve file cursor (`tell`)", - |e| format!("{}; path={}", e, self.path.display())) - } - - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - let err = match self.fd.seek(pos, style) { - Ok(_) => { - // successful seek resets EOF indicator - self.last_nread = -1; - Ok(()) - } - Err(e) => Err(e), - }; - err.update_err("couldn't seek in file", - |e| format!("{}; path={}", e, self.path.display())) - } -} - -/// Utility methods for paths. -#[deprecated(since = "1.0.0", reason = "replaced with std::fs::PathExt")] -#[unstable(feature = "old_io")] -pub trait PathExtensions { - /// Get information on the file, directory, etc at this path. - /// - /// Consult the `fs::stat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::stat`. - fn stat(&self) -> IoResult; - - /// Get information on the file, directory, etc at this path, not following - /// symlinks. - /// - /// Consult the `fs::lstat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::lstat`. - fn lstat(&self) -> IoResult; - - /// Boolean value indicator whether the underlying file exists on the local - /// filesystem. Returns false in exactly the cases where `fs::stat` fails. - fn exists(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) points at a "regular file" on the FS. Will return false for paths - /// to non-existent locations or directories or other non-regular files - /// (named pipes, etc). Follows links when making this determination. - fn is_file(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) is pointing at a directory in the underlying FS. Will return - /// false for paths to non-existent locations or if the item is not a - /// directory (eg files, named pipes, etc). Follows links when making this - /// determination. - fn is_dir(&self) -> bool; -} - -impl PathExtensions for old_path::Path { - fn stat(&self) -> IoResult { stat(self) } - fn lstat(&self) -> IoResult { lstat(self) } - fn exists(&self) -> bool { - self.stat().is_ok() - } - fn is_file(&self) -> bool { - match self.stat() { - Ok(s) => s.kind == FileType::RegularFile, - Err(..) => false - } - } - fn is_dir(&self) -> bool { - match self.stat() { - Ok(s) => s.kind == FileType::Directory, - Err(..) => false - } - } -} - -fn mode_string(mode: FileMode) -> &'static str { - match mode { - super::Open => "open", - super::Append => "append", - super::Truncate => "truncate" - } -} - -fn access_string(access: FileAccess) -> &'static str { - match access { - super::Read => "read", - super::Write => "write", - super::ReadWrite => "readwrite" - } -} - -#[cfg(test)] -#[allow(unused_imports)] -#[allow(unused_variables)] -#[allow(unused_mut)] -#[allow(deprecated)] // rand -mod test { - use prelude::v1::*; - use old_io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite, FileType}; - use old_io::{self, Reader, Writer, Seek}; - use old_path::{Path, GenericPath}; - use str; - use old_io::fs::*; - - macro_rules! check { ($e:expr) => ( - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {:?}", stringify!($e), e), - } - ) } - - macro_rules! error { ($e:expr, $s:expr) => ( - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!(err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s)) - } - ) } - - pub struct TempDir(Path); - - impl TempDir { - fn join(&self, path: &str) -> Path { - let TempDir(ref p) = *self; - p.join(path) - } - - fn path<'a>(&'a self) -> &'a Path { - let TempDir(ref p) = *self; - p - } - } - - impl Drop for TempDir { - fn drop(&mut self) { - // Gee, seeing how we're testing the fs module I sure hope that we - // at least implement this correctly! - let TempDir(ref p) = *self; - check!(old_io::fs::rmdir_recursive(p)); - } - } - - pub fn tmpdir() -> TempDir { - use os; - use rand; - let temp = Path::new(::env::temp_dir().to_str().unwrap()); - let ret = temp.join(format!("rust-{}", rand::random::())); - check!(old_io::fs::mkdir(&ret, old_io::USER_RWX)); - TempDir(ret) - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = File::open_mode(filename, Open, ReadWrite); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - 0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string() - }; - assert_eq!(read_str, message); - } - check!(unlink(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open_mode(filename, Open, Read); - - error!(result, "couldn't open path as file"); - if cfg!(unix) { - error!(result, "no such file or directory"); - } - error!(result, &format!("path={}; mode=open; access=read", filename.display())); - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = unlink(filename); - - error!(result, "couldn't unlink path"); - if cfg!(unix) { - error!(result, "no such file or directory"); - } - error!(result, &format!("path={}", filename.display())); - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let mut tell_pos_pre_read; - let mut tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - check!(read_stream.seek(set_cursor as i64, SeekSet)); - tell_pos_pre_read = check!(read_stream.tell()); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.tell()); - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(seek_idx as i64, SeekSet)); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - check!(read_stream.read(&mut read_mem)); - } - check!(unlink(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - use str; // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = File::open_mode(filename, Open, ReadWrite); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = File::open_mode(filename, Open, Read); - - check!(read_stream.seek(-4, SeekEnd)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(-9, SeekCur)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(0, SeekSet)); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(unlink(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut fs = check!(File::open_mode(filename, Open, ReadWrite)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.stat()); - assert_eq!(fstat_res.kind, FileType::RegularFile); - } - let stat_res_fn = check!(stat(filename)); - assert_eq!(stat_res_fn.kind, FileType::RegularFile); - let stat_res_meth = check!(filename.stat()); - assert_eq!(stat_res_meth.kind, FileType::RegularFile); - check!(unlink(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(mkdir(filename, old_io::USER_RWX)); - let stat_res_fn = check!(stat(filename)); - assert!(stat_res_fn.kind == FileType::Directory); - let stat_res_meth = check!(filename.stat()); - assert!(stat_res_meth.kind == FileType::Directory); - check!(rmdir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(mkdir(dir, old_io::USER_RWX)); - assert!(dir.is_file() == false); - check!(rmdir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(File::create(file).write(b"foo")); - assert!(file.exists()); - check!(unlink(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(mkdir(dir, old_io::USER_RWX)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(rmdir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - use str; - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(mkdir(dir, old_io::USER_RWX)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(readdir(dir)); - let mut mem = [0; 4]; - for f in &files { - { - let n = f.filestem_str(); - check!(File::open(f).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = match n { - None|Some("") => panic!("really shouldn't happen.."), - Some(n) => format!("{}{}", prefix, n), - }; - assert_eq!(expected, read_str); - } - check!(unlink(f)); - } - check!(rmdir(dir)); - } - - #[test] - fn file_test_walk_dir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("walk_dir"); - check!(mkdir(dir, old_io::USER_RWX)); - - let dir1 = &dir.join("01/02/03"); - check!(mkdir_recursive(dir1, old_io::USER_RWX)); - check!(File::create(&dir1.join("04"))); - - let dir2 = &dir.join("11/12/13"); - check!(mkdir_recursive(dir2, old_io::USER_RWX)); - check!(File::create(&dir2.join("14"))); - - let mut files = check!(walk_dir(dir)); - let mut cur = [0; 2]; - for f in files { - let stem = f.filestem_str().unwrap(); - let root = stem.as_bytes()[0] - b'0'; - let name = stem.as_bytes()[1] - b'0'; - assert!(cur[root as usize] < name); - cur[root as usize] = name; - } - - check!(rmdir_recursive(dir)); - } - - #[test] - fn mkdir_path_already_exists_error() { - use old_io::{IoError, PathAlreadyExists}; - - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(mkdir(dir, old_io::USER_RWX)); - match mkdir(dir, old_io::USER_RWX) { - Err(IoError{kind:PathAlreadyExists,..}) => (), - _ => assert!(false) - }; - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(mkdir_recursive(&dir, old_io::USER_RWX)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(mkdir_recursive(&dir, old_io::USER_RWX)); - check!(File::create(&file)); - - let result = mkdir_recursive(&file, old_io::USER_RWX); - - error!(result, "couldn't recursively mkdir"); - error!(result, "couldn't create directory"); - error!(result, "mode=0700"); - error!(result, &format!("path={}", file.display())); - } - - #[test] - fn recursive_mkdir_slash() { - check!(mkdir_recursive(&Path::new("/"), old_io::USER_RWX)); - } - - // FIXME(#12795) depends on lstat to work on windows - #[cfg(not(windows))] - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(mkdir_recursive(&dtt, old_io::USER_RWX)); - check!(mkdir_recursive(&d2, old_io::USER_RWX)); - check!(File::create(&canary).write(b"foo")); - check!(symlink(&d2, &dt.join("d2"))); - check!(rmdir_recursive(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().clone(); - dirpath.push(format!("test-가一ー你好")); - check!(mkdir(&dirpath, old_io::USER_RWX)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join(format!("test-각丁ー再见")); - check!(mkdir(&unicode, old_io::USER_RWX)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path::new("test/nonexistent-bogus-path"); - let to = Path::new("test/other-bogus-path"); - - error!(copy(&from, &to), - &format!("couldn't copy path (the source path is not an \ - existing file; from={:?}; to={:?})", - from.display(), to.display())); - - match copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write(b"hello")); - check!(copy(&input, &out)); - let contents = check!(File::open(&out).read_to_end()); - assert_eq!(contents, b"hello"); - - assert_eq!(check!(input.stat()).perm, check!(out.stat()).perm); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match copy(&out, tmpdir.path()) { - Ok(..) => panic!(), Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(File::create(&input).write("foo".as_bytes())); - check!(File::create(&output).write("bar".as_bytes())); - check!(copy(&input, &output)); - - assert_eq!(check!(File::open(&output).read_to_end()), - b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match copy(tmpdir.path(), &out) { - Ok(..) => panic!(), Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input)); - check!(chmod(&input, old_io::USER_READ)); - check!(copy(&input, &out)); - assert!(!check!(out.stat()).perm.intersects(old_io::USER_WRITE)); - - check!(chmod(&input, old_io::USER_FILE)); - check!(chmod(&out, old_io::USER_FILE)); - } - - #[cfg(not(windows))] // FIXME(#10264) operation not permitted? - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write("foobar".as_bytes())); - check!(symlink(&input, &out)); - if cfg!(not(windows)) { - assert_eq!(check!(lstat(&out)).kind, FileType::Symlink); - assert_eq!(check!(out.lstat()).kind, FileType::Symlink); - } - assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); - assert_eq!(check!(File::open(&out).read_to_end()), - b"foobar".to_vec()); - } - - #[cfg(not(windows))] // apparently windows doesn't like symlinks - #[test] - fn symlink_noexist() { - let tmpdir = tmpdir(); - // symlinks can point to things that don't exist - check!(symlink(&tmpdir.join("foo"), &tmpdir.join("bar"))); - assert!(check!(readlink(&tmpdir.join("bar"))) == tmpdir.join("foo")); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match readlink(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(File::create(&input).write("foobar".as_bytes())); - check!(link(&input, &out)); - if cfg!(not(windows)) { - assert_eq!(check!(lstat(&out)).kind, FileType::RegularFile); - assert_eq!(check!(out.lstat()).kind, FileType::RegularFile); - assert_eq!(check!(stat(&out)).unstable.nlink, 2); - assert_eq!(check!(out.stat()).unstable.nlink, 2); - } - assert_eq!(check!(stat(&out)).size, check!(stat(&input)).size); - assert_eq!(check!(stat(&out)).size, check!(input.stat()).size); - assert_eq!(check!(File::open(&out).read_to_end()), - b"foobar".to_vec()); - - // can't link to yourself - match link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - assert!(check!(stat(&file)).perm.contains(old_io::USER_WRITE)); - check!(chmod(&file, old_io::USER_READ)); - assert!(!check!(stat(&file)).perm.contains(old_io::USER_WRITE)); - - match chmod(&tmpdir.join("foo"), old_io::USER_RWX) { - Ok(..) => panic!("wanted a panic"), - Err(..) => {} - } - - check!(chmod(&file, old_io::USER_FILE)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite)); - check!(file.fsync()); - check!(file.datasync()); - check!(file.write(b"foo")); - check!(file.fsync()); - check!(file.datasync()); - drop(file); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::open_mode(&path, old_io::Open, old_io::ReadWrite)); - check!(file.write(b"foo")); - check!(file.fsync()); - - // Do some simple things with truncation - assert_eq!(check!(file.stat()).size, 3); - check!(file.truncate(10)); - assert_eq!(check!(file.stat()).size, 10); - check!(file.write(b"bar")); - check!(file.fsync()); - assert_eq!(check!(file.stat()).size, 10); - assert_eq!(check!(File::open(&path).read_to_end()), - b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.truncate(2)); - assert_eq!(check!(file.stat()).size, 2); - check!(file.write(b"wut")); - check!(file.fsync()); - assert_eq!(check!(file.stat()).size, 9); - assert_eq!(check!(File::open(&path).read_to_end()), - b"fo\0\0\0\0wut".to_vec()); - drop(file); - } - - #[test] - fn open_flavors() { - let tmpdir = tmpdir(); - - match File::open_mode(&tmpdir.join("a"), old_io::Open, old_io::Read) { - Ok(..) => panic!(), Err(..) => {} - } - - // Perform each one twice to make sure that it succeeds the second time - // (where the file exists) - check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write)); - assert!(tmpdir.join("b").exists()); - check!(File::open_mode(&tmpdir.join("b"), old_io::Open, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite)); - assert!(tmpdir.join("c").exists()); - check!(File::open_mode(&tmpdir.join("c"), old_io::Open, old_io::ReadWrite)); - - check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write)); - assert!(tmpdir.join("d").exists()); - check!(File::open_mode(&tmpdir.join("d"), old_io::Append, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite)); - assert!(tmpdir.join("e").exists()); - check!(File::open_mode(&tmpdir.join("e"), old_io::Append, old_io::ReadWrite)); - - check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write)); - assert!(tmpdir.join("f").exists()); - check!(File::open_mode(&tmpdir.join("f"), old_io::Truncate, old_io::Write)); - - check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite)); - assert!(tmpdir.join("g").exists()); - check!(File::open_mode(&tmpdir.join("g"), old_io::Truncate, old_io::ReadWrite)); - - check!(File::create(&tmpdir.join("h")).write("foo".as_bytes())); - check!(File::open_mode(&tmpdir.join("h"), old_io::Open, old_io::Read)); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Open, - old_io::Read)); - match f.write("wut".as_bytes()) { - Ok(..) => panic!(), Err(..) => {} - } - } - assert!(check!(stat(&tmpdir.join("h"))).size == 3, - "write/stat failed"); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Append, - old_io::Write)); - check!(f.write("bar".as_bytes())); - } - assert!(check!(stat(&tmpdir.join("h"))).size == 6, - "append didn't append"); - { - let mut f = check!(File::open_mode(&tmpdir.join("h"), old_io::Truncate, - old_io::Write)); - check!(f.write("bar".as_bytes())); - } - assert!(check!(stat(&tmpdir.join("h"))).size == 3, - "truncate didn't truncate"); - } - - #[test] - fn utime() { - let tmpdir = tmpdir(); - let path = tmpdir.join("a"); - check!(File::create(&path)); - // These numbers have to be bigger than the time in the day to account - // for timezones Windows in particular will fail in certain timezones - // with small enough values - check!(change_file_times(&path, 100000, 200000)); - assert_eq!(check!(path.stat()).accessed, 100000); - assert_eq!(check!(path.stat()).modified, 200000); - } - - #[test] - fn utime_noexist() { - let tmpdir = tmpdir(); - - match change_file_times(&tmpdir.join("a"), 100, 200) { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn binary_file() { - use rand::{StdRng, Rng}; - - let mut bytes = [0; 1024]; - StdRng::new().unwrap().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(File::create(&tmpdir.join("test")).write(&bytes)); - let actual = check!(File::open(&tmpdir.join("test")).read_to_end()); - assert!(actual == &bytes[..]); - } - - #[test] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - check!(chmod(&path, old_io::USER_READ)); - check!(unlink(&path)); - } -} diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs deleted file mode 100644 index c92e74fbc5..0000000000 --- a/src/libstd/old_io/mem.rs +++ /dev/null @@ -1,765 +0,0 @@ -// Copyright 2013 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. -// -// ignore-lexer-test FIXME #15679 - -//! Readers and Writers for in-memory buffers - -use cmp::min; -use option::Option::None; -use result::Result::{Err, Ok}; -use old_io; -use old_io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; -use slice; -use vec::Vec; - -const BUF_CAPACITY: usize = 128; - -fn combine(seek: SeekStyle, cur: usize, end: usize, offset: i64) -> IoResult { - // compute offset as signed and clamp to prevent overflow - let pos = match seek { - old_io::SeekSet => 0, - old_io::SeekEnd => end, - old_io::SeekCur => cur, - } as i64; - - if offset + pos < 0 { - Err(IoError { - kind: old_io::InvalidInput, - desc: "invalid seek to a negative offset", - detail: None - }) - } else { - Ok((offset + pos) as u64) - } -} - -impl Writer for Vec { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.push_all(buf); - Ok(()) - } -} - -/// Writes to an owned, growable byte vector -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, io)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// -/// let mut w = MemWriter::new(); -/// w.write(&[0, 1, 2]); -/// -/// assert_eq!(w.into_inner(), [0, 1, 2]); -/// ``` -#[unstable(feature = "io")] -#[deprecated(since = "1.0.0", - reason = "use the Vec Writer implementation directly")] -#[derive(Clone)] -#[allow(deprecated)] -pub struct MemWriter { - buf: Vec, -} - -#[allow(deprecated)] -impl MemWriter { - /// Create a new `MemWriter`. - #[inline] - pub fn new() -> MemWriter { - MemWriter::with_capacity(BUF_CAPACITY) - } - /// Create a new `MemWriter`, allocating at least `n` bytes for - /// the internal buffer. - #[inline] - pub fn with_capacity(n: usize) -> MemWriter { - MemWriter::from_vec(Vec::with_capacity(n)) - } - /// Create a new `MemWriter` that will append to an existing `Vec`. - #[inline] - pub fn from_vec(buf: Vec) -> MemWriter { - MemWriter { buf: buf } - } - - /// Acquires an immutable reference to the underlying buffer of this - /// `MemWriter`. - #[inline] - pub fn get_ref<'a>(&'a self) -> &'a [u8] { &self.buf } - - /// Unwraps this `MemWriter`, returning the underlying buffer - #[inline] - pub fn into_inner(self) -> Vec { self.buf } -} - -impl Writer for MemWriter { - #[inline] - #[allow(deprecated)] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.buf.push_all(buf); - Ok(()) - } -} - -/// Reads from an owned byte vector -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// -/// let mut r = MemReader::new(vec!(0, 1, 2)); -/// -/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]); -/// ``` -pub struct MemReader { - buf: Vec, - pos: usize -} - -impl MemReader { - /// Creates a new `MemReader` which will read the buffer given. The buffer - /// can be re-acquired through `unwrap` - #[inline] - pub fn new(buf: Vec) -> MemReader { - MemReader { - buf: buf, - pos: 0 - } - } - - /// Tests whether this reader has read all bytes in its buffer. - /// - /// If `true`, then this will no longer return bytes from `read`. - #[inline] - pub fn eof(&self) -> bool { self.pos >= self.buf.len() } - - /// Acquires an immutable reference to the underlying buffer of this - /// `MemReader`. - /// - /// No method is exposed for acquiring a mutable reference to the buffer - /// because it could corrupt the state of this `MemReader`. - #[inline] - pub fn get_ref<'a>(&'a self) -> &'a [u8] { &self.buf } - - /// Unwraps this `MemReader`, returning the underlying buffer - #[inline] - pub fn into_inner(self) -> Vec { self.buf } -} - -impl Reader for MemReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.eof() { return Err(old_io::standard_error(old_io::EndOfFile)) } - - let write_len = min(buf.len(), self.buf.len() - self.pos); - { - let input = &self.buf[self.pos.. self.pos + write_len]; - let output = &mut buf[..write_len]; - assert_eq!(input.len(), output.len()); - slice::bytes::copy_memory(input, output); - } - self.pos += write_len; - assert!(self.pos <= self.buf.len()); - - return Ok(write_len); - } -} - -impl Seek for MemReader { - #[inline] - fn tell(&self) -> IoResult { Ok(self.pos as u64) } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - let new = try!(combine(style, self.pos, self.buf.len(), pos)); - self.pos = new as usize; - Ok(()) - } -} - -impl Buffer for MemReader { - #[inline] - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { - if self.pos < self.buf.len() { - Ok(&self.buf[self.pos..]) - } else { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - #[inline] - fn consume(&mut self, amt: usize) { self.pos += amt; } -} - -impl<'a> Reader for &'a [u8] { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.is_empty() { return Err(old_io::standard_error(old_io::EndOfFile)); } - - let write_len = min(buf.len(), self.len()); - { - let input = &self[..write_len]; - let output = &mut buf[.. write_len]; - slice::bytes::copy_memory(input, output); - } - - *self = &self[write_len..]; - - Ok(write_len) - } -} - -impl<'a> Buffer for &'a [u8] { - #[inline] - fn fill_buf(&mut self) -> IoResult<&[u8]> { - if self.is_empty() { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(*self) - } - } - - #[inline] - fn consume(&mut self, amt: usize) { - *self = &self[amt..]; - } -} - - -/// Writes to a fixed-size byte slice -/// -/// If a write will not fit in the buffer, it returns an error and does not -/// write any data. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, io)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// -/// let mut buf = [0; 4]; -/// { -/// let mut w = BufWriter::new(&mut buf); -/// w.write(&[0, 1, 2]); -/// } -/// assert!(buf == [0, 1, 2, 0]); -/// ``` -pub struct BufWriter<'a> { - buf: &'a mut [u8], - pos: usize -} - -impl<'a> BufWriter<'a> { - /// Creates a new `BufWriter` which will wrap the specified buffer. The - /// writer initially starts at position 0. - #[inline] - pub fn new(buf: &'a mut [u8]) -> BufWriter<'a> { - BufWriter { - buf: buf, - pos: 0 - } - } -} - -impl<'a> Writer for BufWriter<'a> { - #[inline] - fn write_all(&mut self, src: &[u8]) -> IoResult<()> { - let dst = &mut self.buf[self.pos..]; - let dst_len = dst.len(); - - if dst_len == 0 { - return Err(old_io::standard_error(old_io::EndOfFile)); - } - - let src_len = src.len(); - - if dst_len >= src_len { - slice::bytes::copy_memory(src, dst); - - self.pos += src_len; - - Ok(()) - } else { - slice::bytes::copy_memory(&src[..dst_len], dst); - - self.pos += dst_len; - - Err(old_io::standard_error(old_io::ShortWrite(dst_len))) - } - } -} - -impl<'a> Seek for BufWriter<'a> { - #[inline] - fn tell(&self) -> IoResult { Ok(self.pos as u64) } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - let new = try!(combine(style, self.pos, self.buf.len(), pos)); - self.pos = min(new as usize, self.buf.len()); - Ok(()) - } -} - -/// Reads from a fixed-size byte slice -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// # #![allow(unused_must_use)] -/// use std::old_io::*; -/// -/// let buf = [0, 1, 2, 3]; -/// let mut r = BufReader::new(&buf); -/// -/// assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]); -/// ``` -pub struct BufReader<'a> { - buf: &'a [u8], - pos: usize -} - -impl<'a> BufReader<'a> { - /// Creates a new buffered reader which will read the specified buffer - #[inline] - pub fn new(buf: &'a [u8]) -> BufReader<'a> { - BufReader { - buf: buf, - pos: 0 - } - } - - /// Tests whether this reader has read all bytes in its buffer. - /// - /// If `true`, then this will no longer return bytes from `read`. - #[inline] - pub fn eof(&self) -> bool { self.pos >= self.buf.len() } -} - -impl<'a> Reader for BufReader<'a> { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.eof() { return Err(old_io::standard_error(old_io::EndOfFile)) } - - let write_len = min(buf.len(), self.buf.len() - self.pos); - { - let input = &self.buf[self.pos.. self.pos + write_len]; - let output = &mut buf[..write_len]; - assert_eq!(input.len(), output.len()); - slice::bytes::copy_memory(input, output); - } - self.pos += write_len; - assert!(self.pos <= self.buf.len()); - - return Ok(write_len); - } -} - -impl<'a> Seek for BufReader<'a> { - #[inline] - fn tell(&self) -> IoResult { Ok(self.pos as u64) } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - let new = try!(combine(style, self.pos, self.buf.len(), pos)); - self.pos = new as usize; - Ok(()) - } -} - -impl<'a> Buffer for BufReader<'a> { - #[inline] - fn fill_buf(&mut self) -> IoResult<&[u8]> { - if self.pos < self.buf.len() { - Ok(&self.buf[self.pos..]) - } else { - Err(old_io::standard_error(old_io::EndOfFile)) - } - } - - #[inline] - fn consume(&mut self, amt: usize) { self.pos += amt; } -} - -#[cfg(test)] -mod test { - extern crate test as test_crate; - use old_io::{SeekSet, SeekCur, SeekEnd, Reader, Writer, Seek, Buffer}; - use prelude::v1::{Ok, Err, Vec}; - use prelude::v1::Iterator; - use old_io; - use iter::repeat; - use self::test_crate::Bencher; - use super::*; - - #[test] - fn test_vec_writer() { - let mut writer = Vec::new(); - writer.write(&[0]).unwrap(); - writer.write(&[1, 2, 3]).unwrap(); - writer.write(&[4, 5, 6, 7]).unwrap(); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(writer, b); - } - - #[test] - fn test_mem_writer() { - let mut writer = MemWriter::new(); - writer.write(&[0]).unwrap(); - writer.write(&[1, 2, 3]).unwrap(); - writer.write(&[4, 5, 6, 7]).unwrap(); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(writer.get_ref(), b); - } - - #[test] - fn test_buf_writer() { - let mut buf = [0 as u8; 9]; - { - let mut writer = BufWriter::new(&mut buf); - assert_eq!(writer.tell(), Ok(0)); - writer.write(&[0]).unwrap(); - assert_eq!(writer.tell(), Ok(1)); - writer.write(&[1, 2, 3]).unwrap(); - writer.write(&[4, 5, 6, 7]).unwrap(); - assert_eq!(writer.tell(), Ok(8)); - writer.write(&[]).unwrap(); - assert_eq!(writer.tell(), Ok(8)); - - assert_eq!(writer.write(&[8, 9]).err().unwrap().kind, old_io::ShortWrite(1)); - assert_eq!(writer.write(&[10]).err().unwrap().kind, old_io::EndOfFile); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_seek() { - let mut buf = [0 as u8; 8]; - { - let mut writer = BufWriter::new(&mut buf); - assert_eq!(writer.tell(), Ok(0)); - writer.write(&[1]).unwrap(); - assert_eq!(writer.tell(), Ok(1)); - - writer.seek(2, SeekSet).unwrap(); - assert_eq!(writer.tell(), Ok(2)); - writer.write(&[2]).unwrap(); - assert_eq!(writer.tell(), Ok(3)); - - writer.seek(-2, SeekCur).unwrap(); - assert_eq!(writer.tell(), Ok(1)); - writer.write(&[3]).unwrap(); - assert_eq!(writer.tell(), Ok(2)); - - writer.seek(-1, SeekEnd).unwrap(); - assert_eq!(writer.tell(), Ok(7)); - writer.write(&[4]).unwrap(); - assert_eq!(writer.tell(), Ok(8)); - - } - let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_error() { - let mut buf = [0 as u8; 2]; - let mut writer = BufWriter::new(&mut buf); - writer.write(&[0]).unwrap(); - - match writer.write(&[0, 0]) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::ShortWrite(1)), - } - } - - #[test] - fn test_mem_reader() { - let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); - let mut buf = []; - assert_eq!(reader.read(&mut buf), Ok(0)); - assert_eq!(reader.tell(), Ok(0)); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf), Ok(1)); - assert_eq!(reader.tell(), Ok(1)); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf), Ok(4)); - assert_eq!(reader.tell(), Ok(5)); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf), Ok(3)); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert!(reader.read(&mut buf).is_err()); - let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); - assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]); - assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]); - assert!(reader.read(&mut buf).is_err()); - } - - #[test] - fn test_slice_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = &mut &*in_buf; - let mut buf = []; - assert_eq!(reader.read(&mut buf), Ok(0)); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf), Ok(1)); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf), Ok(4)); - assert_eq!(reader.len(), 3); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf), Ok(3)); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert!(reader.read(&mut buf).is_err()); - let mut reader = &mut &*in_buf; - assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]); - assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]); - assert!(reader.read(&mut buf).is_err()); - } - - #[test] - fn test_buf_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = BufReader::new(&in_buf); - let mut buf = []; - assert_eq!(reader.read(&mut buf), Ok(0)); - assert_eq!(reader.tell(), Ok(0)); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf), Ok(1)); - assert_eq!(reader.tell(), Ok(1)); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf), Ok(4)); - assert_eq!(reader.tell(), Ok(5)); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf), Ok(3)); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert!(reader.read(&mut buf).is_err()); - let mut reader = BufReader::new(&in_buf); - assert_eq!(reader.read_until(3).unwrap(), [0, 1, 2, 3]); - assert_eq!(reader.read_until(3).unwrap(), [4, 5, 6, 7]); - assert!(reader.read(&mut buf).is_err()); - } - - #[test] - fn test_read_char() { - let b = b"Vi\xE1\xBB\x87t"; - let mut r = BufReader::new(b); - assert_eq!(r.read_char(), Ok('V')); - assert_eq!(r.read_char(), Ok('i')); - assert_eq!(r.read_char(), Ok('ệ')); - assert_eq!(r.read_char(), Ok('t')); - assert!(r.read_char().is_err()); - } - - #[test] - fn test_read_bad_char() { - let b = b"\x80"; - let mut r = BufReader::new(b); - assert!(r.read_char().is_err()); - } - - #[test] - fn test_write_strings() { - let mut writer = MemWriter::new(); - writer.write_str("testing").unwrap(); - writer.write_line("testing").unwrap(); - writer.write_str("testing").unwrap(); - let mut r = BufReader::new(writer.get_ref()); - assert_eq!(r.read_to_string().unwrap(), "testingtesting\ntesting"); - } - - #[test] - fn test_write_char() { - let mut writer = MemWriter::new(); - writer.write_char('a').unwrap(); - writer.write_char('\n').unwrap(); - writer.write_char('ệ').unwrap(); - let mut r = BufReader::new(writer.get_ref()); - assert_eq!(r.read_to_string().unwrap(), "a\nệ"); - } - - #[test] - fn test_read_whole_string_bad() { - let buf = [0xff]; - let mut r = BufReader::new(&buf); - match r.read_to_string() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn seek_past_end() { - let buf = [0xff]; - let mut r = BufReader::new(&buf); - r.seek(10, SeekSet).unwrap(); - assert!(r.read(&mut []).is_err()); - - let mut r = MemReader::new(vec!(10)); - r.seek(10, SeekSet).unwrap(); - assert!(r.read(&mut []).is_err()); - - let mut buf = [0]; - let mut r = BufWriter::new(&mut buf); - r.seek(10, SeekSet).unwrap(); - assert!(r.write(&[3]).is_err()); - } - - #[test] - fn seek_before_0() { - let buf = [0xff]; - let mut r = BufReader::new(&buf); - assert!(r.seek(-1, SeekSet).is_err()); - - let mut r = MemReader::new(vec!(10)); - assert!(r.seek(-1, SeekSet).is_err()); - - let mut buf = [0]; - let mut r = BufWriter::new(&mut buf); - assert!(r.seek(-1, SeekSet).is_err()); - } - - #[test] - fn io_read_at_least() { - let mut r = MemReader::new(vec![1, 2, 3, 4, 5, 6, 7, 8]); - let mut buf = [0; 3]; - assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); - let b: &[_] = &[1, 2, 3]; - assert_eq!(buf, b); - assert!(r.read_at_least(0, &mut buf[..0]).is_ok()); - assert_eq!(buf, b); - assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); - let b: &[_] = &[4, 5, 6]; - assert_eq!(buf, b); - assert!(r.read_at_least(buf.len(), &mut buf).is_err()); - let b: &[_] = &[7, 8, 6]; - assert_eq!(buf, b); - } - - fn do_bench_mem_writer(b: &mut Bencher, times: usize, len: usize) { - let src: Vec = repeat(5).take(len).collect(); - - b.bytes = (times * len) as u64; - b.iter(|| { - let mut wr = MemWriter::new(); - for _ in 0..times { - wr.write(&src).unwrap(); - } - - let v = wr.into_inner(); - assert_eq!(v.len(), times * len); - assert!(v.iter().all(|x| *x == 5)); - }); - } - - #[bench] - fn bench_mem_writer_001_0000(b: &mut Bencher) { - do_bench_mem_writer(b, 1, 0) - } - - #[bench] - fn bench_mem_writer_001_0010(b: &mut Bencher) { - do_bench_mem_writer(b, 1, 10) - } - - #[bench] - fn bench_mem_writer_001_0100(b: &mut Bencher) { - do_bench_mem_writer(b, 1, 100) - } - - #[bench] - fn bench_mem_writer_001_1000(b: &mut Bencher) { - do_bench_mem_writer(b, 1, 1000) - } - - #[bench] - fn bench_mem_writer_100_0000(b: &mut Bencher) { - do_bench_mem_writer(b, 100, 0) - } - - #[bench] - fn bench_mem_writer_100_0010(b: &mut Bencher) { - do_bench_mem_writer(b, 100, 10) - } - - #[bench] - fn bench_mem_writer_100_0100(b: &mut Bencher) { - do_bench_mem_writer(b, 100, 100) - } - - #[bench] - fn bench_mem_writer_100_1000(b: &mut Bencher) { - do_bench_mem_writer(b, 100, 1000) - } - - #[bench] - fn bench_mem_reader(b: &mut Bencher) { - b.iter(|| { - let buf = [5 as u8; 100].to_vec(); - { - let mut rdr = MemReader::new(buf); - for _i in 0..10 { - let mut buf = [0 as u8; 10]; - rdr.read(&mut buf).unwrap(); - assert_eq!(buf, [5; 10]); - } - } - }); - } - - #[bench] - fn bench_buf_writer(b: &mut Bencher) { - b.iter(|| { - let mut buf = [0 as u8; 100]; - { - let mut wr = BufWriter::new(&mut buf); - for _i in 0..10 { - wr.write(&[5; 10]).unwrap(); - } - } - assert_eq!(&buf[..], &[5; 100][..]); - }); - } - - #[bench] - fn bench_buf_reader(b: &mut Bencher) { - b.iter(|| { - let buf = [5 as u8; 100]; - { - let mut rdr = BufReader::new(&buf); - for _i in 0..10 { - let mut buf = [0 as u8; 10]; - rdr.read(&mut buf).unwrap(); - assert_eq!(buf, [5; 10]); - } - } - }); - } -} diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs deleted file mode 100644 index 98ff6e82c6..0000000000 --- a/src/libstd/old_io/mod.rs +++ /dev/null @@ -1,1984 +0,0 @@ -// Copyright 2013-2014 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. -// -// ignore-lexer-test FIXME #15883 - -// FIXME: cover these topics: -// path, reader, writer, stream, raii (close not needed), -// stdio, print!, println!, file access, process spawning, -// error handling - - -//! I/O, including files, networking, timers, and processes -//! -//! > **Warning**: This module is currently called `old_io` for a reason! The -//! > module is currently being redesigned in a number of RFCs. For more details -//! > follow the RFC repository in connection with [RFC 517][base] or follow -//! > some of these sub-RFCs -//! > -//! > * [String handling][osstr] -//! > * [Core I/O support][core] -//! > * [Deadlines][deadlines] -//! > * [std::env][env] -//! > * [std::process][process] -//! -//! [base]: https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md -//! [osstr]: https://github.com/rust-lang/rfcs/pull/575 -//! [core]: https://github.com/rust-lang/rfcs/pull/576 -//! [deadlines]: https://github.com/rust-lang/rfcs/pull/577 -//! [env]: https://github.com/rust-lang/rfcs/pull/578 -//! [process]: https://github.com/rust-lang/rfcs/pull/579 -//! -//! `std::io` provides Rust's basic I/O types, -//! for reading and writing to files, TCP, UDP, -//! and other types of sockets and pipes, -//! manipulating the file system, spawning processes. -//! -//! # Examples -//! -//! Some examples of obvious things you might want to do -//! -//! * Read lines from stdin -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! use std::old_io as io; -//! use std::old_io::*; -//! -//! let mut stdin = io::stdin(); -//! for line in stdin.lock().lines() { -//! print!("{}", line.unwrap()); -//! } -//! ``` -//! -//! * Read a complete file -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let contents = File::open(&Path::new("message.txt")).read_to_end(); -//! ``` -//! -//! * Write a line to a file -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let mut file = File::create(&Path::new("message.txt")); -//! file.write_all(b"hello, file!\n"); -//! # drop(file); -//! # ::std::old_io::fs::unlink(&Path::new("message.txt")); -//! ``` -//! -//! * Iterate over the lines of a file -//! -//! ```rust,no_run -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("message.txt"); -//! let mut file = BufferedReader::new(File::open(&path)); -//! for line in file.lines() { -//! print!("{}", line.unwrap()); -//! } -//! ``` -//! -//! * Pull the lines of a file into a vector of strings -//! -//! ```rust,no_run -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! let path = Path::new("message.txt"); -//! let mut file = BufferedReader::new(File::open(&path)); -//! let lines: Vec = file.lines().map(|x| x.unwrap()).collect(); -//! ``` -//! -//! * Make a simple TCP client connection and request -//! -//! ```rust -//! # #![feature(old_io)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! -//! # // connection doesn't fail if a server is running on 8080 -//! # // locally, we still want to be type checking this code, so lets -//! # // just stop it running (#11576) -//! # if false { -//! let mut socket = TcpStream::connect("127.0.0.1:8080").unwrap(); -//! socket.write_all(b"GET / HTTP/1.0\n\n"); -//! let response = socket.read_to_end(); -//! # } -//! ``` -//! -//! * Make a simple TCP server -//! -//! ```rust -//! # #![feature(old_io)] -//! # fn main() { } -//! # fn foo() { -//! # #![allow(dead_code)] -//! use std::old_io::*; -//! use std::thread; -//! -//! let listener = TcpListener::bind("127.0.0.1:80"); -//! -//! // bind the listener to the specified address -//! let mut acceptor = listener.listen(); -//! -//! fn handle_client(mut stream: TcpStream) { -//! // ... -//! # &mut stream; // silence unused mutability/variable warning -//! } -//! // accept connections and process them, spawning a new tasks for each one -//! for stream in acceptor.incoming() { -//! match stream { -//! Err(e) => { /* connection failed */ } -//! Ok(stream) => { -//! thread::spawn(move|| { -//! // connection succeeded -//! handle_client(stream) -//! }); -//! } -//! } -//! } -//! -//! // close the socket server -//! drop(acceptor); -//! # } -//! ``` -//! -//! -//! # Error Handling -//! -//! I/O is an area where nearly every operation can result in unexpected -//! errors. Errors should be painfully visible when they happen, and handling them -//! should be easy to work with. It should be convenient to handle specific I/O -//! errors, and it should also be convenient to not deal with I/O errors. -//! -//! Rust's I/O employs a combination of techniques to reduce boilerplate -//! while still providing feedback about errors. The basic strategy: -//! -//! * All I/O operations return `IoResult` which is equivalent to -//! `Result`. The `Result` type is defined in the `std::result` -//! module. -//! * If the `Result` type goes unused, then the compiler will by default emit a -//! warning about the unused result. This is because `Result` has the -//! `#[must_use]` attribute. -//! * Common traits are implemented for `IoResult`, e.g. -//! `impl Reader for IoResult`, so that error values do not have -//! to be 'unwrapped' before use. -//! -//! These features combine in the API to allow for expressions like -//! `File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n")` -//! without having to worry about whether "diary.txt" exists or whether -//! the write succeeds. As written, if either `new` or `write_line` -//! encounters an error then the result of the entire expression will -//! be an error. -//! -//! If you wanted to handle the error though you might write: -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! # #![allow(unused_must_use)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! match File::create(&Path::new("diary.txt")).write_all(b"Met a girl.\n") { -//! Ok(()) => (), // succeeded -//! Err(e) => println!("failed to write to my diary: {}", e), -//! } -//! -//! # ::std::old_io::fs::unlink(&Path::new("diary.txt")); -//! ``` -//! -//! So what actually happens if `create` encounters an error? -//! It's important to know that what `new` returns is not a `File` -//! but an `IoResult`. If the file does not open, then `new` will simply -//! return `Err(..)`. Because there is an implementation of `Writer` (the trait -//! required ultimately required for types to implement `write_line`) there is no -//! need to inspect or unwrap the `IoResult` and we simply call `write_line` -//! on it. If `new` returned an `Err(..)` then the followup call to `write_line` -//! will also return an error. -//! -//! ## `try!` -//! -//! Explicit pattern matching on `IoResult`s can get quite verbose, especially -//! when performing many I/O operations. Some examples (like those above) are -//! alleviated with extra methods implemented on `IoResult`, but others have more -//! complex interdependencies among each I/O operation. -//! -//! The `try!` macro from `std::macros` is provided as a method of early-return -//! inside `Result`-returning functions. It expands to an early-return on `Err` -//! and otherwise unwraps the contained `Ok` value. -//! -//! If you wanted to read several `u32`s from a file and return their product: -//! -//! ```rust -//! # #![feature(old_io, old_path)] -//! use std::old_io::*; -//! use std::old_path::Path; -//! -//! fn file_product(p: &Path) -> IoResult { -//! let mut f = File::open(p); -//! let x1 = try!(f.read_le_u32()); -//! let x2 = try!(f.read_le_u32()); -//! -//! Ok(x1 * x2) -//! } -//! -//! match file_product(&Path::new("numbers.bin")) { -//! Ok(x) => println!("{}", x), -//! Err(e) => println!("Failed to read numbers!") -//! } -//! ``` -//! -//! With `try!` in `file_product`, each `read_le_u32` need not be directly -//! concerned with error handling; instead its caller is responsible for -//! responding to errors that may occur while attempting to read the numbers. - -#![unstable(feature = "old_io")] -#![deny(unused_must_use)] -#![allow(deprecated)] // seriously this is all deprecated -#![allow(unused_imports)] -#![deprecated(since = "1.0.0", - reasons = "APIs have been replaced with new I/O modules such as \ - std::{io, fs, net, process}")] - -pub use self::SeekStyle::*; -pub use self::FileMode::*; -pub use self::FileAccess::*; -pub use self::IoErrorKind::*; - -use default::Default; -use error::Error; -use fmt; -use isize; -use iter::Iterator; -use marker::{PhantomFn, Sized}; -use mem::transmute; -use ops::FnOnce; -use option::Option; -use option::Option::{Some, None}; -use sys::os; -use boxed::Box; -use result::Result; -use result::Result::{Ok, Err}; -use sys; -use str; -use string::String; -use usize; -use unicode; -use vec::Vec; - -// Reexports -pub use self::stdio::stdin; -pub use self::stdio::stdout; -pub use self::stdio::stderr; -pub use self::stdio::print; -pub use self::stdio::println; - -pub use self::fs::File; -pub use self::timer::Timer; -pub use self::net::ip::IpAddr; -pub use self::net::tcp::TcpListener; -pub use self::net::tcp::TcpStream; -pub use self::pipe::PipeStream; -pub use self::process::{Process, Command}; -pub use self::tempfile::TempDir; - -pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; -pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream, - LineBufferedWriter}; -pub use self::comm_adapters::{ChanReader, ChanWriter}; - -mod buffered; -mod comm_adapters; -mod mem; -mod result; -mod tempfile; -pub mod extensions; -pub mod fs; -pub mod net; -pub mod pipe; -pub mod process; -pub mod stdio; -pub mod timer; -pub mod util; - -#[macro_use] -pub mod test; - -/// The default buffer size for various I/O operations -// libuv recommends 64k buffers to maximize throughput -// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA -const DEFAULT_BUF_SIZE: usize = 1024 * 64; - -/// A convenient typedef of the return value of any I/O action. -pub type IoResult = Result; - -/// The type passed to I/O condition handlers to indicate error -/// -/// # FIXME -/// -/// Is something like this sufficient? It's kind of archaic -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct IoError { - /// An enumeration which can be matched against for determining the flavor - /// of error. - pub kind: IoErrorKind, - /// A human-readable description about the error - pub desc: &'static str, - /// Detailed information about this error, not always available - pub detail: Option -} - -impl IoError { - /// Convert an `errno` value into an `IoError`. - /// - /// If `detail` is `true`, the `detail` field of the `IoError` - /// struct is filled with an allocated string describing the error - /// in more detail, retrieved from the operating system. - pub fn from_errno(errno: i32, detail: bool) -> IoError { - let mut err = sys::decode_error(errno as i32); - if detail && err.kind == OtherIoError { - err.detail = Some(os::error_string(errno).to_lowercase()); - } - err - } - - /// Retrieve the last error to occur as a (detailed) IoError. - /// - /// This uses the OS `errno`, and so there should not be any task - /// descheduling or migration (other than that performed by the - /// operating system) between the call(s) for which errors are - /// being checked and the call of this function. - pub fn last_error() -> IoError { - IoError::from_errno(os::errno(), true) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for IoError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - IoError { kind: OtherIoError, desc: "unknown error", detail: Some(ref detail) } => - write!(fmt, "{}", detail), - IoError { detail: None, desc, .. } => - write!(fmt, "{}", desc), - IoError { detail: Some(ref detail), desc, .. } => - write!(fmt, "{} ({})", desc, detail) - } - } -} - -impl Error for IoError { - fn description(&self) -> &str { self.desc } -} - -/// A list specifying general categories of I/O error. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum IoErrorKind { - /// Any I/O error not part of this list. - OtherIoError, - /// The operation could not complete because end of file was reached. - EndOfFile, - /// The file was not found. - FileNotFound, - /// The file permissions disallowed access to this file. - PermissionDenied, - /// A network connection failed for some reason not specified in this list. - ConnectionFailed, - /// The network operation failed because the network connection was closed. - Closed, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// A file already existed with that name. - PathAlreadyExists, - /// No file exists at that location. - PathDoesntExist, - /// The path did not specify the type of file that this operation required. For example, - /// attempting to copy a directory with the `fs::copy()` operation will fail with this error. - MismatchedFileTypeForOperation, - /// The operation temporarily failed (for example, because a signal was received), and retrying - /// may succeed. - ResourceUnavailable, - /// No I/O functionality is available for this task. - IoUnavailable, - /// A parameter was incorrect in a way that caused an I/O error not part of this list. - InvalidInput, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// This write operation failed to write all of its data. - /// - /// Normally the write() method on a Writer guarantees that all of its data - /// has been written, but some operations may be terminated after only - /// partially writing some data. An example of this is a timed out write - /// which successfully wrote a known number of bytes, but bailed out after - /// doing so. - /// - /// The payload contained as part of this variant is the number of bytes - /// which are known to have been successfully written. - ShortWrite(usize), - /// The Reader returned 0 bytes from `read()` too many times. - NoProgress, -} - -/// A trait that lets you add a `detail` to an IoError easily -trait UpdateIoError { - /// Returns an IoError with updated description and detail - fn update_err(self, desc: &'static str, detail: D) -> Self where - D: FnOnce(&IoError) -> String; - - /// Returns an IoError with updated detail - fn update_detail(self, detail: D) -> Self where - D: FnOnce(&IoError) -> String; - - /// Returns an IoError with update description - fn update_desc(self, desc: &'static str) -> Self; -} - -impl UpdateIoError for IoResult { - fn update_err(self, desc: &'static str, detail: D) -> IoResult where - D: FnOnce(&IoError) -> String, - { - self.map_err(move |mut e| { - let detail = detail(&e); - e.desc = desc; - e.detail = Some(detail); - e - }) - } - - fn update_detail(self, detail: D) -> IoResult where - D: FnOnce(&IoError) -> String, - { - self.map_err(move |mut e| { e.detail = Some(detail(&e)); e }) - } - - fn update_desc(self, desc: &'static str) -> IoResult { - self.map_err(|mut e| { e.desc = desc; e }) - } -} - -static NO_PROGRESS_LIMIT: usize = 1000; - -/// A trait for objects which are byte-oriented streams. Readers are defined by -/// one method, `read`. This function will block until data is available, -/// filling in the provided buffer with any data read. -/// -/// Readers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Reader` trait. -pub trait Reader { - - // Only method which need to get implemented for this trait - - /// Read bytes, up to the length of `buf` and place them in `buf`. - /// Returns the number of bytes read. The number of bytes read may - /// be less than the number requested, even 0. Returns `Err` on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned as - /// `Err(IoError)`. Note that end-of-file is considered an error, and can be - /// inspected for in the error's `kind` field. Also note that reading 0 - /// bytes is not considered an error in all circumstances - /// - /// # Implementation Note - /// - /// When implementing this method on a new Reader, you are strongly encouraged - /// not to return 0 if you can avoid it. - fn read(&mut self, buf: &mut [u8]) -> IoResult; - - // Convenient helper methods based on the above methods - - /// Reads at least `min` bytes and places them in `buf`. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn read_at_least(&mut self, min: usize, buf: &mut [u8]) -> IoResult { - if min > buf.len() { - return Err(IoError { - detail: Some(String::from_str("the buffer is too short")), - ..standard_error(InvalidInput) - }); - } - let mut read = 0; - while read < min { - let mut zeroes = 0; - loop { - match self.read(&mut buf[read..]) { - Ok(0) => { - zeroes += 1; - if zeroes >= NO_PROGRESS_LIMIT { - return Err(standard_error(NoProgress)); - } - } - Ok(n) => { - read += n; - break; - } - err@Err(_) => return err - } - } - } - Ok(read) - } - - /// Reads a single byte. Returns `Err` on EOF. - fn read_byte(&mut self) -> IoResult { - let mut buf = [0]; - try!(self.read_at_least(1, &mut buf)); - Ok(buf[0]) - } - - /// Reads up to `len` bytes and appends them to a vector. - /// Returns the number of bytes read. The number of bytes read may be - /// less than the number requested, even 0. Returns Err on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned - /// as `Err(IoError)`. See `read()` for more details. - fn push(&mut self, len: usize, buf: &mut Vec) -> IoResult { - let start_len = buf.len(); - buf.reserve(len); - - let n = { - let s = unsafe { slice_vec_capacity(buf, start_len, start_len + len) }; - try!(self.read(s)) - }; - unsafe { buf.set_len(start_len + n) }; - Ok(n) - } - - /// Reads at least `min` bytes, but no more than `len`, and appends them to - /// a vector. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec) -> IoResult { - if min > len { - return Err(IoError { - detail: Some(String::from_str("the buffer is too short")), - ..standard_error(InvalidInput) - }); - } - - let start_len = buf.len(); - buf.reserve(len); - - // we can't just use self.read_at_least(min, slice) because we need to push - // successful reads onto the vector before any returned errors. - - let mut read = 0; - while read < min { - read += { - let s = unsafe { slice_vec_capacity(buf, start_len + read, start_len + len) }; - try!(self.read_at_least(1, s)) - }; - unsafe { buf.set_len(start_len + read) }; - } - Ok(read) - } - - /// Reads exactly `len` bytes and gives you back a new vector of length - /// `len` - /// - /// # Error - /// - /// Fails with the same conditions as `read`. Additionally returns error - /// on EOF. Note that if an error is returned, then some number of bytes may - /// have already been consumed from the underlying reader, and they are lost - /// (not returned as part of the error). If this is unacceptable, then it is - /// recommended to use the `push_at_least` or `read` methods. - fn read_exact(&mut self, len: usize) -> IoResult> { - let mut buf = Vec::with_capacity(len); - match self.push_at_least(len, len, &mut buf) { - Ok(_) => Ok(buf), - Err(e) => Err(e), - } - } - - /// Reads all remaining bytes from the stream. - /// - /// # Error - /// - /// Returns any non-EOF error immediately. Previously read bytes are - /// discarded when an error is returned. - /// - /// When EOF is encountered, all bytes read up to that point are returned. - fn read_to_end(&mut self) -> IoResult> { - let mut buf = Vec::with_capacity(DEFAULT_BUF_SIZE); - loop { - match self.push_at_least(1, DEFAULT_BUF_SIZE, &mut buf) { - Ok(_) => {} - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => return Err(e) - } - } - return Ok(buf); - } - - /// Reads all of the remaining bytes of this stream, interpreting them as a - /// UTF-8 encoded stream. The corresponding string is returned. - /// - /// # Error - /// - /// This function returns all of the same errors as `read_to_end` with an - /// additional error if the reader's contents are not a valid sequence of - /// UTF-8 bytes. - fn read_to_string(&mut self) -> IoResult { - self.read_to_end().and_then(|s| { - match String::from_utf8(s) { - Ok(s) => Ok(s), - Err(_) => Err(standard_error(InvalidInput)), - } - }) - } - - // Byte conversion helpers - - /// Reads `n` little-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0; - let mut pos = 0; - let mut i = nbytes; - while i > 0 { - val += (try!(self.read_u8()) as u64) << pos; - pos += 8; - i -= 1; - } - Ok(val) - } - - /// Reads `n` little-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: usize) -> IoResult { - self.read_le_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) - } - - /// Reads `n` big-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0; - let mut i = nbytes; - while i > 0 { - i -= 1; - val += (try!(self.read_u8()) as u64) << i * 8; - } - Ok(val) - } - - /// Reads `n` big-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: usize) -> IoResult { - self.read_be_uint_n(nbytes).map(|i| extend_sign(i, nbytes)) - } - - /// Reads a little-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_uint(&mut self) -> IoResult { - self.read_le_uint_n(usize::BYTES as usize).map(|i| i as usize) - } - - /// Reads a little-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_int(&mut self) -> IoResult { - self.read_le_int_n(isize::BYTES as usize).map(|i| i as isize) - } - - /// Reads a big-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_uint(&mut self) -> IoResult { - self.read_be_uint_n(usize::BYTES as usize).map(|i| i as usize) - } - - /// Reads a big-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_int(&mut self) -> IoResult { - self.read_be_int_n(isize::BYTES as usize).map(|i| i as isize) - } - - /// Reads a big-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> IoResult { - self.read_be_uint_n(8) - } - - /// Reads a big-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> IoResult { - self.read_be_uint_n(4).map(|i| i as u32) - } - - /// Reads a big-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> IoResult { - self.read_be_uint_n(2).map(|i| i as u16) - } - - /// Reads a big-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> IoResult { - self.read_be_int_n(8) - } - - /// Reads a big-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> IoResult { - self.read_be_int_n(4).map(|i| i as i32) - } - - /// Reads a big-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> IoResult { - self.read_be_int_n(2).map(|i| i as i16) - } - - /// Reads a big-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> IoResult { - self.read_be_u64().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a big-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> IoResult { - self.read_be_u32().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a little-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> IoResult { - self.read_le_uint_n(8) - } - - /// Reads a little-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> IoResult { - self.read_le_uint_n(4).map(|i| i as u32) - } - - /// Reads a little-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> IoResult { - self.read_le_uint_n(2).map(|i| i as u16) - } - - /// Reads a little-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> IoResult { - self.read_le_int_n(8) - } - - /// Reads a little-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> IoResult { - self.read_le_int_n(4).map(|i| i as i32) - } - - /// Reads a little-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> IoResult { - self.read_le_int_n(2).map(|i| i as i16) - } - - /// Reads a little-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> IoResult { - self.read_le_u64().map(|i| unsafe { - transmute::(i) - }) - } - - /// Reads a little-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> IoResult { - self.read_le_u32().map(|i| unsafe { - transmute::(i) - }) - } - - /// Read a u8. - /// - /// `u8`s are 1 byte. - fn read_u8(&mut self) -> IoResult { - self.read_byte() - } - - /// Read an i8. - /// - /// `i8`s are 1 byte. - fn read_i8(&mut self) -> IoResult { - self.read_byte().map(|i| i as i8) - } -} - -/// A reader which can be converted to a RefReader. -pub trait ByRefReader { - /// Creates a wrapper around a mutable reference to the reader. - /// - /// This is useful to allow applying adaptors while still - /// retaining ownership of the original value. - fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; -} - -impl ByRefReader for T { - fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { - RefReader { inner: self } - } -} - -/// A reader which can be converted to bytes. -pub trait BytesReader { - /// Create an iterator that reads a single byte on - /// each iteration, until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self>; -} - -impl BytesReader for T { - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { - extensions::Bytes::new(self) - } -} - -impl<'a> Reader for Box { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let reader: &mut Reader = &mut **self; - reader.read(buf) - } -} - -impl<'a> Reader for &'a mut (Reader+'a) { - fn read(&mut self, buf: &mut [u8]) -> IoResult { (*self).read(buf) } -} - -/// Returns a slice of `v` between `start` and `end`. -/// -/// Similar to `slice()` except this function only bounds the slice on the -/// capacity of `v`, not the length. -/// -/// # Panics -/// -/// Panics when `start` or `end` point outside the capacity of `v`, or when -/// `start` > `end`. -// Private function here because we aren't sure if we want to expose this as -// API yet. If so, it should be a method on Vec. -unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: usize, end: usize) -> &'a mut [T] { - use slice; - - assert!(start <= end); - assert!(end <= v.capacity()); - slice::from_raw_parts_mut( - v.as_mut_ptr().offset(start as isize), - end - start - ) -} - -/// A `RefReader` is a struct implementing `Reader` which contains a reference -/// to another reader. This is often useful when composing streams. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io as io; -/// use std::old_io::*; -/// use std::old_io::util::LimitReader; -/// -/// fn process_input(r: R) {} -/// -/// let mut stream = io::stdin(); -/// -/// // Only allow the function to process at most one kilobyte of input -/// { -/// let stream = LimitReader::new(stream.by_ref(), 1024); -/// process_input(stream); -/// } -/// -/// // 'stream' is still available for use here -/// ``` -pub struct RefReader<'a, R:'a> { - /// The underlying reader which this is referencing - inner: &'a mut R -} - -impl<'a, R: Reader> Reader for RefReader<'a, R> { - fn read(&mut self, buf: &mut [u8]) -> IoResult { self.inner.read(buf) } -} - -impl<'a, R: Buffer> Buffer for RefReader<'a, R> { - fn fill_buf(&mut self) -> IoResult<&[u8]> { self.inner.fill_buf() } - fn consume(&mut self, amt: usize) { self.inner.consume(amt) } -} - -fn extend_sign(val: u64, nbytes: usize) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -/// A trait for objects which are byte-oriented streams. Writers are defined by -/// one method, `write`. This function will block until the provided buffer of -/// bytes has been entirely written, and it will return any failures which occur. -/// -/// Another commonly overridden method is the `flush` method for writers such as -/// buffered writers. -/// -/// Writers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Writer` trait. -pub trait Writer { - /// Write the entirety of a given buffer - /// - /// # Errors - /// - /// If an error happens during the I/O operation, the error is returned as - /// `Err`. Note that it is considered an error if the entire buffer could - /// not be written, and if an error is returned then it is unknown how much - /// data (if any) was actually written. - fn write_all(&mut self, buf: &[u8]) -> IoResult<()>; - - /// Deprecated, this method was renamed to `write_all` - #[unstable(feature = "io")] - #[deprecated(since = "1.0.0", reason = "renamed to `write_all`")] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.write_all(buf) } - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// This is by default a no-op and implementers of the `Writer` trait should - /// decide whether their stream needs to be buffered or not. - fn flush(&mut self) -> IoResult<()> { Ok(()) } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the `format_args!` - /// macro, but it is rare that this should explicitly be called. The - /// `write!` macro should be favored to invoke this method instead. - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - fn write_fmt(&mut self, fmt: fmt::Arguments) -> IoResult<()> { - // Create a shim which translates a Writer to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized +'a> { - inner: &'a mut T, - error: IoResult<()>, - } - - impl<'a, T: ?Sized + Writer> fmt::Write for Adaptor<'a, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adaptor { inner: self, error: Ok(()) }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => output.error - } - } - - - /// Write a rust string into this sink. - /// - /// The bytes written will be the UTF-8 encoded version of the input string. - /// If other encodings are desired, it is recommended to compose this stream - /// with another performing the conversion, or to use `write` with a - /// converted byte-array instead. - #[inline] - fn write_str(&mut self, s: &str) -> IoResult<()> { - self.write_all(s.as_bytes()) - } - - /// Writes a string into this sink, and then writes a literal newline (`\n`) - /// byte afterwards. Note that the writing of the newline is *not* atomic in - /// the sense that the call to `write` is invoked twice (once with the - /// string and once with a newline character). - /// - /// If other encodings or line ending flavors are desired, it is recommended - /// that the `write` method is used specifically instead. - #[inline] - fn write_line(&mut self, s: &str) -> IoResult<()> { - self.write_str(s).and_then(|()| self.write_all(&[b'\n'])) - } - - /// Write a single char, encoded as UTF-8. - #[inline] - fn write_char(&mut self, c: char) -> IoResult<()> { - let mut buf = [0; 4]; - let n = c.encode_utf8(&mut buf).unwrap_or(0); - self.write_all(&buf[..n]) - } - - /// Write the result of passing n through `isize::to_str_bytes`. - #[inline] - fn write_int(&mut self, n: isize) -> IoResult<()> { - write!(self, "{}", n) - } - - /// Write the result of passing n through `usize::to_str_bytes`. - #[inline] - fn write_uint(&mut self, n: usize) -> IoResult<()> { - write!(self, "{}", n) - } - - /// Write a little-endian usize (number of bytes depends on system). - #[inline] - fn write_le_uint(&mut self, n: usize) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, usize::BYTES as usize, |v| self.write_all(v)) - } - - /// Write a little-endian isize (number of bytes depends on system). - #[inline] - fn write_le_int(&mut self, n: isize) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, isize::BYTES as usize, |v| self.write_all(v)) - } - - /// Write a big-endian usize (number of bytes depends on system). - #[inline] - fn write_be_uint(&mut self, n: usize) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, usize::BYTES as usize, |v| self.write_all(v)) - } - - /// Write a big-endian isize (number of bytes depends on system). - #[inline] - fn write_be_int(&mut self, n: isize) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, isize::BYTES as usize, |v| self.write_all(v)) - } - - /// Write a big-endian u64 (8 bytes). - #[inline] - fn write_be_u64(&mut self, n: u64) -> IoResult<()> { - extensions::u64_to_be_bytes(n, 8, |v| self.write_all(v)) - } - - /// Write a big-endian u32 (4 bytes). - #[inline] - fn write_be_u32(&mut self, n: u32) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a big-endian u16 (2 bytes). - #[inline] - fn write_be_u16(&mut self, n: u16) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a big-endian i64 (8 bytes). - #[inline] - fn write_be_i64(&mut self, n: i64) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 8, |v| self.write_all(v)) - } - - /// Write a big-endian i32 (4 bytes). - #[inline] - fn write_be_i32(&mut self, n: i32) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a big-endian i16 (2 bytes). - #[inline] - fn write_be_i16(&mut self, n: i16) -> IoResult<()> { - extensions::u64_to_be_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - #[inline] - fn write_be_f64(&mut self, f: f64) -> IoResult<()> { - unsafe { - self.write_be_u64(transmute(f)) - } - } - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - #[inline] - fn write_be_f32(&mut self, f: f32) -> IoResult<()> { - unsafe { - self.write_be_u32(transmute(f)) - } - } - - /// Write a little-endian u64 (8 bytes). - #[inline] - fn write_le_u64(&mut self, n: u64) -> IoResult<()> { - extensions::u64_to_le_bytes(n, 8, |v| self.write_all(v)) - } - - /// Write a little-endian u32 (4 bytes). - #[inline] - fn write_le_u32(&mut self, n: u32) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a little-endian u16 (2 bytes). - #[inline] - fn write_le_u16(&mut self, n: u16) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a little-endian i64 (8 bytes). - #[inline] - fn write_le_i64(&mut self, n: i64) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 8, |v| self.write_all(v)) - } - - /// Write a little-endian i32 (4 bytes). - #[inline] - fn write_le_i32(&mut self, n: i32) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 4, |v| self.write_all(v)) - } - - /// Write a little-endian i16 (2 bytes). - #[inline] - fn write_le_i16(&mut self, n: i16) -> IoResult<()> { - extensions::u64_to_le_bytes(n as u64, 2, |v| self.write_all(v)) - } - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - #[inline] - fn write_le_f64(&mut self, f: f64) -> IoResult<()> { - unsafe { - self.write_le_u64(transmute(f)) - } - } - - /// Write a little-endian IEEE754 single-precision floating-point - /// (4 bytes). - #[inline] - fn write_le_f32(&mut self, f: f32) -> IoResult<()> { - unsafe { - self.write_le_u32(transmute(f)) - } - } - - /// Write a u8 (1 byte). - #[inline] - fn write_u8(&mut self, n: u8) -> IoResult<()> { - self.write_all(&[n]) - } - - /// Write an i8 (1 byte). - #[inline] - fn write_i8(&mut self, n: i8) -> IoResult<()> { - self.write_all(&[n as u8]) - } -} - -/// A writer which can be converted to a RefWriter. -pub trait ByRefWriter { - /// Creates a wrapper around a mutable reference to the writer. - /// - /// This is useful to allow applying wrappers while still - /// retaining ownership of the original value. - #[inline] - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; -} - -impl ByRefWriter for T { - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { - RefWriter { inner: self } - } -} - -impl<'a> Writer for Box { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - (&mut **self).write_all(buf) - } - - #[inline] - fn flush(&mut self) -> IoResult<()> { - (&mut **self).flush() - } -} - -impl<'a> Writer for &'a mut (Writer+'a) { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { (**self).write_all(buf) } - - #[inline] - fn flush(&mut self) -> IoResult<()> { (**self).flush() } -} - -/// A `RefWriter` is a struct implementing `Writer` which contains a reference -/// to another writer. This is often useful when composing streams. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io::util::TeeReader; -/// use std::old_io::*; -/// -/// fn process_input(r: R) {} -/// -/// let mut output = Vec::new(); -/// -/// { -/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a -/// // handle to it in the outer scope -/// let mut tee = TeeReader::new(stdin(), output.by_ref()); -/// process_input(tee); -/// } -/// -/// println!("input processed: {:?}", output); -/// ``` -pub struct RefWriter<'a, W:'a> { - /// The underlying writer which this is referencing - inner: &'a mut W -} - -impl<'a, W: Writer> Writer for RefWriter<'a, W> { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { self.inner.write_all(buf) } - - #[inline] - fn flush(&mut self) -> IoResult<()> { self.inner.flush() } -} - - -/// A Stream is a readable and a writable object. Data written is typically -/// received by the object which reads receive data from. -pub trait Stream: Reader + Writer { } - -impl Stream for T {} - -/// An iterator that reads a line on each iteration, -/// until `.read_line()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Lines` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Lines<'r, T:'r> { - buffer: &'r mut T, -} - -impl<'r, T: Buffer> Iterator for Lines<'r, T> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - match self.buffer.read_line() { - Ok(x) => Some(Ok(x)), - Err(IoError { kind: EndOfFile, ..}) => None, - Err(y) => Some(Err(y)) - } - } -} - -/// An iterator that reads a utf8-encoded character on each iteration, -/// until `.read_char()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Chars` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Chars<'r, T:'r> { - buffer: &'r mut T -} - -impl<'r, T: Buffer> Iterator for Chars<'r, T> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - match self.buffer.read_char() { - Ok(x) => Some(Ok(x)), - Err(IoError { kind: EndOfFile, ..}) => None, - Err(y) => Some(Err(y)) - } - } -} - -/// A Buffer is a type of reader which has some form of internal buffering to -/// allow certain kinds of reading operations to be more optimized than others. -/// This type extends the `Reader` trait with a few methods that are not -/// possible to reasonably implement with purely a read interface. -pub trait Buffer: Reader { - /// Fills the internal buffer of this object, returning the buffer contents. - /// Note that none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. - /// - /// The `consume` function must be called with the number of bytes that are - /// consumed from this buffer returned to ensure that the bytes are never - /// returned twice. - /// - /// # Error - /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. Note that it is not an error to return a - /// 0-length buffer. - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. - fn consume(&mut self, amt: usize); - - /// Reads the next line of input, interpreted as a sequence of UTF-8 - /// encoded Unicode codepoints. If a newline is encountered, then the - /// newline is contained in the returned string. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io::*; - /// - /// let mut reader = BufReader::new(b"hello\nworld"); - /// assert_eq!("hello\n", &*reader.read_line().unwrap()); - /// ``` - /// - /// # Error - /// - /// This function has the same error semantics as `read_until`: - /// - /// * All non-EOF errors will be returned immediately - /// * If an error is returned previously consumed bytes are lost - /// * EOF is only returned if no bytes have been read - /// * Reach EOF may mean that the delimiter is not present in the return - /// value - /// - /// Additionally, this function can fail if the line of input read is not a - /// valid UTF-8 sequence of bytes. - fn read_line(&mut self) -> IoResult { - self.read_until(b'\n').and_then(|line| - match String::from_utf8(line) { - Ok(s) => Ok(s), - Err(_) => Err(standard_error(InvalidInput)), - } - ) - } - - /// Reads a sequence of bytes leading up to a specified delimiter. Once the - /// specified byte is encountered, reading ceases and the bytes up to and - /// including the delimiter are returned. - /// - /// # Error - /// - /// If any I/O error is encountered other than EOF, the error is immediately - /// returned. Note that this may discard bytes which have already been read, - /// and those bytes will *not* be returned. It is recommended to use other - /// methods if this case is worrying. - /// - /// If EOF is encountered, then this function will return EOF if 0 bytes - /// have been read, otherwise the pending byte buffer is returned. This - /// is the reason that the byte buffer returned may not always contain the - /// delimiter. - fn read_until(&mut self, byte: u8) -> IoResult> { - let mut res = Vec::new(); - - loop { - let (done, used) = { - let available = match self.fill_buf() { - Ok(n) => n, - Err(ref e) if res.len() > 0 && e.kind == EndOfFile => { - return Ok(res); - } - Err(e) => return Err(e) - }; - match available.iter().position(|&b| b == byte) { - Some(i) => { - res.push_all(&available[..i + 1]); - (true, i + 1) - } - None => { - res.push_all(available); - (false, available.len()) - } - } - }; - self.consume(used); - if done { - return Ok(res); - } - } - } - - /// Reads the next utf8-encoded character from the underlying stream. - /// - /// # Error - /// - /// If an I/O error occurs, or EOF, then this function will return `Err`. - /// This function will also return error if the stream does not contain a - /// valid utf-8 encoded codepoint as the next few bytes in the stream. - fn read_char(&mut self) -> IoResult { - let first_byte = try!(self.read_byte()); - let width = unicode::str::utf8_char_width(first_byte); - if width == 1 { return Ok(first_byte as char) } - if width == 0 { return Err(standard_error(InvalidInput)) } // not utf8 - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match try!(self.read(&mut buf[start .. width])) { - n if n == width - start => break, - n if n < width - start => { start += n; } - _ => return Err(standard_error(InvalidInput)), - } - } - } - match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.char_at(0)), - None => Err(standard_error(InvalidInput)) - } - } -} - -/// Extension methods for the Buffer trait which are included in the prelude. -pub trait BufferPrelude { - /// Create an iterator that reads a utf8-encoded character on each iteration - /// until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn chars<'r>(&'r mut self) -> Chars<'r, Self>; - - /// Create an iterator that reads a line on each iteration until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn lines<'r>(&'r mut self) -> Lines<'r, Self>; -} - -impl BufferPrelude for T { - fn chars<'r>(&'r mut self) -> Chars<'r, T> { - Chars { buffer: self } - } - - fn lines<'r>(&'r mut self) -> Lines<'r, T> { - Lines { buffer: self } - } -} - -/// When seeking, the resulting cursor is offset from a base by the offset given -/// to the `seek` function. The base used is specified by this enumeration. -#[derive(Copy, Clone)] -pub enum SeekStyle { - /// Seek from the beginning of the stream - SeekSet, - /// Seek from the end of the stream - SeekEnd, - /// Seek from the current position - SeekCur, -} - -/// An object implementing `Seek` internally has some form of cursor which can -/// be moved within a stream of bytes. The stream typically has a fixed size, -/// allowing seeking relative to either end. -pub trait Seek { - /// Return position of file cursor in the stream - fn tell(&self) -> IoResult; - - /// Seek to an offset in a stream - /// - /// A successful seek clears the EOF indicator. Seeking beyond EOF is - /// allowed, but seeking before position 0 is not allowed. - /// - /// # Errors - /// - /// * Seeking to a negative offset is considered an error - /// * Seeking past the end of the stream does not modify the underlying - /// stream, but the next write may cause the previous data to be filled in - /// with a bit pattern. - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; -} - -/// A listener is a value that can consume itself to start listening for -/// connections. -/// -/// Doing so produces some sort of Acceptor. -pub trait Listener { - /// Spin up the listener and start queuing incoming connections - /// - /// # Error - /// - /// Returns `Err` if this listener could not be bound to listen for - /// connections. In all cases, this listener is consumed. - fn listen(self) -> IoResult; -} - -/// An acceptor is a value that presents incoming connections -pub trait Acceptor { - /// Type of connection that is accepted by this acceptor. - type Connection; - - /// Wait for and accept an incoming connection - /// - /// # Error - /// - /// Returns `Err` if an I/O error is encountered. - fn accept(&mut self) -> IoResult; - - /// Create an iterator over incoming connection attempts. - /// - /// Note that I/O errors will be yielded by the iterator itself. - fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { - IncomingConnections { inc: self } - } -} - -/// An infinite iterator over incoming connection attempts. -/// Calling `next` will block the task until a connection is attempted. -/// -/// Since connection attempts can continue forever, this iterator always returns -/// `Some`. The `Some` contains the `IoResult` representing whether the -/// connection attempt was successful. A successful connection will be wrapped -/// in `Ok`. A failed connection is represented as an `Err`. -pub struct IncomingConnections<'a, A: ?Sized +'a> { - inc: &'a mut A, -} - -impl<'a, A: ?Sized + Acceptor> Iterator for IncomingConnections<'a, A> { - type Item = IoResult; - - fn next(&mut self) -> Option> { - Some(self.inc.accept()) - } -} - -/// Creates a standard error for a commonly used flavor of error. The `detail` -/// field of the returned error will always be `None`. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io as io; -/// -/// let eof = io::standard_error(io::EndOfFile); -/// let einval = io::standard_error(io::InvalidInput); -/// ``` -pub fn standard_error(kind: IoErrorKind) -> IoError { - let desc = match kind { - EndOfFile => "end of file", - IoUnavailable => "I/O is unavailable", - InvalidInput => "invalid input", - OtherIoError => "unknown I/O error", - FileNotFound => "file not found", - PermissionDenied => "permission denied", - ConnectionFailed => "connection failed", - Closed => "stream is closed", - ConnectionRefused => "connection refused", - ConnectionReset => "connection reset", - ConnectionAborted => "connection aborted", - NotConnected => "not connected", - BrokenPipe => "broken pipe", - PathAlreadyExists => "file already exists", - PathDoesntExist => "no such file", - MismatchedFileTypeForOperation => "mismatched file type", - ResourceUnavailable => "resource unavailable", - TimedOut => "operation timed out", - ShortWrite(..) => "short write", - NoProgress => "no progress", - }; - IoError { - kind: kind, - desc: desc, - detail: None, - } -} - -/// A mode specifies how a file should be opened or created. These modes are -/// passed to `File::open_mode` and are used to control where the file is -/// positioned when it is initially opened. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum FileMode { - /// Opens a file positioned at the beginning. - Open, - /// Opens a file positioned at EOF. - Append, - /// Opens a file, truncating it if it already exists. - Truncate, -} - -/// Access permissions with which the file should be opened. `File`s -/// opened with `Read` will return an error if written to. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum FileAccess { - /// Read-only access, requests to write will result in an error - Read, - /// Write-only access, requests to read will result in an error - Write, - /// Read-write access, no requests are denied by default - ReadWrite, -} - -/// Different kinds of files which can be identified by a call to stat -#[derive(Copy, PartialEq, Debug, Hash, Clone)] -pub enum FileType { - /// This is a normal file, corresponding to `S_IFREG` - RegularFile, - - /// This file is a directory, corresponding to `S_IFDIR` - Directory, - - /// This file is a named pipe, corresponding to `S_IFIFO` - NamedPipe, - - /// This file is a block device, corresponding to `S_IFBLK` - BlockSpecial, - - /// This file is a symbolic link to another file, corresponding to `S_IFLNK` - Symlink, - - /// The type of this file is not recognized as one of the other categories - Unknown, -} - -/// A structure used to describe metadata information about a file. This -/// structure is created through the `stat` method on a `Path`. -/// -/// # Examples -/// -/// ```no_run -/// # #![feature(old_io, old_path)] -/// -/// use std::old_io::fs::PathExtensions; -/// use std::old_path::Path; -/// -/// let info = match Path::new("foo.txt").stat() { -/// Ok(stat) => stat, -/// Err(e) => panic!("couldn't read foo.txt: {}", e), -/// }; -/// -/// println!("byte size: {}", info.size); -/// ``` -#[derive(Copy, Clone, Hash)] -pub struct FileStat { - /// The size of the file, in bytes - pub size: u64, - /// The kind of file this path points to (directory, file, pipe, etc.) - pub kind: FileType, - /// The file permissions currently on the file - pub perm: FilePermission, - - // FIXME(#10301): These time fields are pretty useless without an actual - // time representation, what are the milliseconds relative - // to? - - /// The time that the file was created at, in platform-dependent - /// milliseconds - pub created: u64, - /// The time that this file was last modified, in platform-dependent - /// milliseconds - pub modified: u64, - /// The time that this file was last accessed, in platform-dependent - /// milliseconds - pub accessed: u64, - - /// Information returned by stat() which is not guaranteed to be - /// platform-independent. This information may be useful on some platforms, - /// but it may have different meanings or no meaning at all on other - /// platforms. - /// - /// Usage of this field is discouraged, but if access is desired then the - /// fields are located here. - #[unstable(feature = "io")] - pub unstable: UnstableFileStat, -} - -/// This structure represents all of the possible information which can be -/// returned from a `stat` syscall which is not contained in the `FileStat` -/// structure. This information is not necessarily platform independent, and may -/// have different meanings or no meaning at all on some platforms. -#[unstable(feature = "io")] -#[derive(Copy, Clone, Hash)] -pub struct UnstableFileStat { - /// The ID of the device containing the file. - pub device: u64, - /// The file serial number. - pub inode: u64, - /// The device ID. - pub rdev: u64, - /// The number of hard links to this file. - pub nlink: u64, - /// The user ID of the file. - pub uid: u64, - /// The group ID of the file. - pub gid: u64, - /// The optimal block size for I/O. - pub blksize: u64, - /// The blocks allocated for this file. - pub blocks: u64, - /// User-defined flags for the file. - pub flags: u64, - /// The file generation number. - pub gen: u64, -} - - -bitflags! { - /// A set of permissions for a file or directory is represented by a set of - /// flags which are or'd together. - #[derive(Debug)] - flags FilePermission: u32 { - const USER_READ = 0o400, - const USER_WRITE = 0o200, - const USER_EXECUTE = 0o100, - const GROUP_READ = 0o040, - const GROUP_WRITE = 0o020, - const GROUP_EXECUTE = 0o010, - const OTHER_READ = 0o004, - const OTHER_WRITE = 0o002, - const OTHER_EXECUTE = 0o001, - - const USER_RWX = USER_READ.bits | USER_WRITE.bits | USER_EXECUTE.bits, - const GROUP_RWX = GROUP_READ.bits | GROUP_WRITE.bits | GROUP_EXECUTE.bits, - const OTHER_RWX = OTHER_READ.bits | OTHER_WRITE.bits | OTHER_EXECUTE.bits, - - /// Permissions for user owned files, equivalent to 0644 on unix-like - /// systems. - const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, - - /// Permissions for user owned directories, equivalent to 0755 on - /// unix-like systems. - const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | - OTHER_READ.bits | OTHER_EXECUTE.bits, - - /// Permissions for user owned executables, equivalent to 0755 - /// on unix-like systems. - const USER_EXEC = USER_DIR.bits, - - /// All possible permissions enabled. - const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, - } -} - - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for FilePermission { - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - fn default() -> FilePermission { FilePermission::empty() } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for FilePermission { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:04o}", self.bits) - } -} - -#[cfg(test)] -mod tests { - use self::BadReaderBehavior::*; - use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer}; - use super::Buffer; - use prelude::v1::{Ok, Vec}; - use usize; - - #[derive(Clone, PartialEq, Debug)] - enum BadReaderBehavior { - GoodBehavior(usize), - BadBehavior(usize) - } - - struct BadReader { - r: T, - behavior: Vec, - } - - impl BadReader { - fn new(r: T, behavior: Vec) -> BadReader { - BadReader { behavior: behavior, r: r } - } - } - - impl Reader for BadReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let BadReader { ref mut behavior, ref mut r } = *self; - loop { - if behavior.is_empty() { - // fall back on good - return r.read(buf); - } - match (&mut **behavior)[0] { - GoodBehavior(0) => (), - GoodBehavior(ref mut x) => { - *x -= 1; - return r.read(buf); - } - BadBehavior(0) => (), - BadBehavior(ref mut x) => { - *x -= 1; - return Ok(0); - } - }; - behavior.remove(0); - } - } - } - - #[test] - fn test_read_at_least() { - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(usize::MAX)]); - let buf = &mut [0; 5]; - assert!(r.read_at_least(1, buf).unwrap() >= 1); - assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least - assert!(r.read_at_least(0, buf).is_ok()); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(1), GoodBehavior(1), - BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - assert!(r.read_at_least(1, buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(usize::MAX)]); - assert_eq!(r.read_at_least(1, buf).unwrap_err().kind, NoProgress); - - let mut r = MemReader::new(b"hello, world!".to_vec()); - assert_eq!(r.read_at_least(5, buf).unwrap(), 5); - assert_eq!(r.read_at_least(6, buf).unwrap_err().kind, InvalidInput); - } - - #[test] - fn test_push_at_least() { - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![GoodBehavior(usize::MAX)]); - let mut buf = Vec::new(); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - assert!(r.push_at_least(0, 5, &mut buf).is_ok()); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(1), GoodBehavior(1), - BadBehavior(50), GoodBehavior(usize::MAX)]); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1); - - let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), - vec![BadBehavior(usize::MAX)]); - assert_eq!(r.push_at_least(1, 5, &mut buf).unwrap_err().kind, NoProgress); - - let mut r = MemReader::new(b"hello, world!".to_vec()); - assert_eq!(r.push_at_least(5, 1, &mut buf).unwrap_err().kind, InvalidInput); - } - - #[test] - fn test_show() { - use super::*; - - assert_eq!(format!("{}", USER_READ), "0400"); - assert_eq!(format!("{}", USER_FILE), "0644"); - assert_eq!(format!("{}", USER_EXEC), "0755"); - assert_eq!(format!("{}", USER_RWX), "0700"); - assert_eq!(format!("{}", GROUP_RWX), "0070"); - assert_eq!(format!("{}", OTHER_RWX), "0007"); - assert_eq!(format!("{}", ALL_PERMISSIONS), "0777"); - assert_eq!(format!("{}", USER_READ | USER_WRITE | OTHER_WRITE), "0602"); - } - - fn _ensure_buffer_is_object_safe(x: &T) -> &Buffer { - x as &Buffer - } -} diff --git a/src/libstd/old_io/net/addrinfo.rs b/src/libstd/old_io/net/addrinfo.rs deleted file mode 100644 index c5fa775ab4..0000000000 --- a/src/libstd/old_io/net/addrinfo.rs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2013 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. - -//! Synchronous DNS Resolution -//! -//! Contains the functionality to perform DNS resolution or reverse lookup, -//! in a style related to `getaddrinfo()` and `getnameinfo()`, respectively. - -#![allow(missing_docs)] - -pub use self::SocketType::*; -pub use self::Flag::*; -pub use self::Protocol::*; - -use iter::Iterator; -use old_io::IoResult; -use old_io::net::ip::{SocketAddr, IpAddr}; -use option::Option; -use option::Option::{Some, None}; -use string::String; -use sys; -use vec::Vec; - -/// Hints to the types of sockets that are desired when looking up hosts -#[derive(Copy, Clone, Debug)] -pub enum SocketType { - Stream, Datagram, Raw -} - -/// Flags which can be or'd into the `flags` field of a `Hint`. These are used -/// to manipulate how a query is performed. -/// -/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` -#[derive(Copy, Clone, Debug)] -pub enum Flag { - AddrConfig, - All, - CanonName, - NumericHost, - NumericServ, - Passive, - V4Mapped, -} - -/// A transport protocol associated with either a hint or a return value of -/// `lookup` -#[derive(Copy, Clone, Debug)] -pub enum Protocol { - TCP, UDP -} - -/// This structure is used to provide hints when fetching addresses for a -/// remote host to control how the lookup is performed. -/// -/// For details on these fields, see their corresponding definitions via -/// `man -s 3 getaddrinfo` -#[derive(Copy, Clone, Debug)] -pub struct Hint { - pub family: usize, - pub socktype: Option, - pub protocol: Option, - pub flags: usize, -} - -#[derive(Copy, Clone, Debug)] -pub struct Info { - pub address: SocketAddr, - pub family: usize, - pub socktype: Option, - pub protocol: Option, - pub flags: usize, -} - -/// Easy name resolution. Given a hostname, returns the list of IP addresses for -/// that hostname. -pub fn get_host_addresses(host: &str) -> IoResult> { - lookup(Some(host), None, None).map(|a| a.into_iter().map(|i| i.address.ip).collect()) -} - -/// Reverse name resolution. Given an address, returns the corresponding -/// hostname. -pub fn get_address_name(addr: IpAddr) -> IoResult { - sys::addrinfo::get_address_name(addr) -} - -/// Full-fledged resolution. This function will perform a synchronous call to -/// getaddrinfo, controlled by the parameters -/// -/// # Arguments -/// -/// * hostname - an optional hostname to lookup against -/// * servname - an optional service name, listed in the system services -/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this -/// controls lookup -/// -/// FIXME: this is not public because the `Hint` structure is not ready for public -/// consumption just yet. -#[allow(unused_variables)] -fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option) - -> IoResult> { - sys::addrinfo::get_host_addresses(hostname, servname, hint) -} - -// Ignored on android since we cannot give tcp/ip -// permission without help of apk -#[cfg(all(test, not(target_os = "android")))] -mod test { - use prelude::v1::*; - use super::*; - use old_io::net::ip::*; - - #[test] - fn dns_smoke_test() { - let ipaddrs = get_host_addresses("localhost").unwrap(); - let mut found_local = false; - let local_addr = &Ipv4Addr(127, 0, 0, 1); - for addr in &ipaddrs { - found_local = found_local || addr == local_addr; - } - assert!(found_local); - } - - #[ignore] - #[test] - fn issue_10663() { - // Something should happen here, but this certainly shouldn't cause - // everything to die. The actual outcome we don't care too much about. - get_host_addresses("example.com").unwrap(); - } -} diff --git a/src/libstd/old_io/net/ip.rs b/src/libstd/old_io/net/ip.rs deleted file mode 100644 index 099fe657f2..0000000000 --- a/src/libstd/old_io/net/ip.rs +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright 2013 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. - -//! Internet Protocol (IP) addresses. -//! -//! This module contains functions useful for parsing, formatting, and -//! manipulating IP addresses. - -#![allow(missing_docs)] - -pub use self::IpAddr::*; - -use boxed::Box; -use fmt; -use old_io::{self, IoResult, IoError}; -use old_io::net; -use iter::Iterator; -use ops::{FnOnce, FnMut}; -use option::Option; -use option::Option::{None, Some}; -use result::Result::{self, Ok, Err}; -use str::FromStr; -use vec::Vec; - -pub type Port = u16; - -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] -pub enum IpAddr { - Ipv4Addr(u8, u8, u8, u8), - Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - Ipv4Addr(a, b, c, d) => - write!(fmt, "{}.{}.{}.{}", a, b, c, d), - - // Ipv4 Compatible address - Ipv6Addr(0, 0, 0, 0, 0, 0, g, h) => { - write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8) - } - - // Ipv4-Mapped address - Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, g, h) => { - write!(fmt, "::FFFF:{}.{}.{}.{}", (g >> 8) as u8, g as u8, - (h >> 8) as u8, h as u8) - } - - Ipv6Addr(a, b, c, d, e, f, g, h) => - write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}", - a, b, c, d, e, f, g, h) - } - } -} - -#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] -pub struct SocketAddr { - pub ip: IpAddr, - pub port: Port, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.ip { - Ipv4Addr(..) => write!(f, "{}:{}", self.ip, self.port), - Ipv6Addr(..) => write!(f, "[{}]:{}", self.ip, self.port), - } - } -} - -struct Parser<'a> { - // parsing as ASCII, so can use byte array - s: &'a [u8], - pos: usize, -} - -impl<'a> Parser<'a> { - fn new(s: &'a str) -> Parser<'a> { - Parser { - s: s.as_bytes(), - pos: 0, - } - } - - fn is_eof(&self) -> bool { - self.pos == self.s.len() - } - - // Commit only if parser returns Some - fn read_atomically(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - let pos = self.pos; - let r = cb(self); - if r.is_none() { - self.pos = pos; - } - r - } - - // Commit only if parser read till EOF - fn read_till_eof(&mut self, cb: F) -> Option where - F: FnOnce(&mut Parser) -> Option, - { - self.read_atomically(move |p| { - match cb(p) { - Some(x) => if p.is_eof() {Some(x)} else {None}, - None => None, - } - }) - } - - // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option>]) - -> Option { - for pf in parsers { - match self.read_atomically(|p: &mut Parser| pf.call_mut((p,))) { - Some(r) => return Some(r), - None => {} - } - } - None - } - - // Apply 3 parsers sequentially - fn read_seq_3(&mut self, - pa: PA, - pb: PB, - pc: PC) - -> Option<(A, B, C)> where - PA: FnOnce(&mut Parser) -> Option, - PB: FnOnce(&mut Parser) -> Option, - PC: FnOnce(&mut Parser) -> Option, - { - self.read_atomically(move |p| { - let a = pa(p); - let b = if a.is_some() { pb(p) } else { None }; - let c = if b.is_some() { pc(p) } else { None }; - match (a, b, c) { - (Some(a), Some(b), Some(c)) => Some((a, b, c)), - _ => None - } - }) - } - - // Read next char - fn read_char(&mut self) -> Option { - if self.is_eof() { - None - } else { - let r = self.s[self.pos] as char; - self.pos += 1; - Some(r) - } - } - - // Return char and advance iff next char is equal to requested - fn read_given_char(&mut self, c: char) -> Option { - self.read_atomically(|p| { - match p.read_char() { - Some(next) if next == c => Some(next), - _ => None, - } - }) - } - - // Read digit - fn read_digit(&mut self, radix: u8) -> Option { - fn parse_digit(c: char, radix: u8) -> Option { - let c = c as u8; - // assuming radix is either 10 or 16 - if c >= b'0' && c <= b'9' { - Some(c - b'0') - } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { - Some(c - b'a' + 10) - } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { - Some(c - b'A' + 10) - } else { - None - } - } - - self.read_atomically(|p| { - p.read_char().and_then(|c| parse_digit(c, radix)) - }) - } - - fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - let mut r = 0; - let mut digit_count = 0; - loop { - match self.read_digit(radix) { - Some(d) => { - r = r * (radix as u32) + (d as u32); - digit_count += 1; - if digit_count > max_digits || r >= upto { - return None - } - } - None => { - if digit_count == 0 { - return None - } else { - return Some(r) - } - } - }; - } - } - - // Read number, failing if max_digits of number value exceeded - fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) - } - - fn read_ipv4_addr_impl(&mut self) -> Option { - let mut bs = [0; 4]; - let mut i = 0; - while i < 4 { - if i != 0 && self.read_given_char('.').is_none() { - return None; - } - - let octet = self.read_number(10, 3, 0x100).map(|n| n as u8); - match octet { - Some(d) => bs[i] = d, - None => return None, - }; - i += 1; - } - Some(Ipv4Addr(bs[0], bs[1], bs[2], bs[3])) - } - - // Read IPv4 address - fn read_ipv4_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv4_addr_impl()) - } - - fn read_ipv6_addr_impl(&mut self) -> Option { - fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> IpAddr { - assert!(head.len() + tail.len() <= 8); - let mut gs = [0; 8]; - gs.clone_from_slice(head); - gs[(8 - tail.len()) .. 8].clone_from_slice(tail); - Ipv6Addr(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) - } - - fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize) -> (usize, bool) { - let mut i = 0; - while i < limit { - if i < limit - 1 { - let ipv4 = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_ipv4_addr() - } else { - None - } - }); - match ipv4 { - Some(Ipv4Addr(a, b, c, d)) => { - groups[i + 0] = ((a as u16) << 8) | (b as u16); - groups[i + 1] = ((c as u16) << 8) | (d as u16); - return (i + 2, true); - } - _ => {} - } - } - - let group = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_number(16, 4, 0x10000).map(|n| n as u16) - } else { - None - } - }); - match group { - Some(g) => groups[i] = g, - None => return (i, false) - } - i += 1; - } - (i, false) - } - - let mut head = [0; 8]; - let (head_size, head_ipv4) = read_groups(self, &mut head, 8); - - if head_size == 8 { - return Some(Ipv6Addr( - head[0], head[1], head[2], head[3], - head[4], head[5], head[6], head[7])) - } - - // IPv4 part is not allowed before `::` - if head_ipv4 { - return None - } - - // read `::` if previous code parsed less than 8 groups - if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() { - return None; - } - - let mut tail = [0; 8]; - let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size); - Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) - } - - fn read_ipv6_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv6_addr_impl()) - } - - fn read_ip_addr(&mut self) -> Option { - let ipv4_addr: Box<_> = box |p: &mut Parser| p.read_ipv4_addr(); - let ipv6_addr: Box<_> = box |p: &mut Parser| p.read_ipv6_addr(); - self.read_or(&mut [ipv4_addr, ipv6_addr]) - } - - fn read_socket_addr(&mut self) -> Option { - let ip_addr = |p: &mut Parser| { - let ipv4_p: Box<_> = box |p: &mut Parser| p.read_ip_addr(); - let ipv6_p: Box<_> = box |p: &mut Parser| { - let open_br = |p: &mut Parser| p.read_given_char('['); - let ip_addr = |p: &mut Parser| p.read_ipv6_addr(); - let clos_br = |p: &mut Parser| p.read_given_char(']'); - p.read_seq_3::(open_br, ip_addr, clos_br) - .map(|t| match t { (_, ip, _) => ip }) - }; - p.read_or(&mut [ipv4_p, ipv6_p]) - }; - let colon = |p: &mut Parser| p.read_given_char(':'); - let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16); - - // host, colon, port - self.read_seq_3::(ip_addr, colon, port) - .map(|t| match t { (ip, _, port) => SocketAddr { ip: ip, port: port } }) - } -} - -impl FromStr for IpAddr { - type Err = ParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { - Some(s) => Ok(s), - None => Err(ParseError), - } - } -} - -impl FromStr for SocketAddr { - type Err = ParseError; - fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { - Some(s) => Ok(s), - None => Err(ParseError), - } - } -} - -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParseError; - -/// A trait for objects which can be converted or resolved to one or more `SocketAddr` values. -/// -/// Implementing types minimally have to implement either `to_socket_addr` or `to_socket_addr_all` -/// method, and its trivial counterpart will be available automatically. -/// -/// This trait is used for generic address resolution when constructing network objects. -/// By default it is implemented for the following types: -/// -/// * `SocketAddr` - `to_socket_addr` is identity function. -/// -/// * `(IpAddr, u16)` - `to_socket_addr` constructs `SocketAddr` trivially. -/// -/// * `(&str, u16)` - the string should be either a string representation of an IP address -/// expected by `FromStr` implementation for `IpAddr` or a host name. -/// -/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding -/// to that IP address joined with the given port. -/// -/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses -/// for the host name, each joined with the given port. -/// -/// * `&str` - the string should be either a string representation of a `SocketAddr` as -/// expected by its `FromStr` implementation or a string like `:` pair -/// where `` is a `u16` value. -/// -/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding -/// to that socket address. -/// -/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses -/// for the host name, each joined with the port. -/// -/// -/// This trait allows constructing network objects like `TcpStream` or `UdpSocket` easily with -/// values of various types for the bind/connection address. It is needed because sometimes -/// one type is more appropriate than the other: for simple uses a string like `"localhost:12345"` -/// is much nicer than manual construction of the corresponding `SocketAddr`, but sometimes -/// `SocketAddr` value is *the* main source of the address, and converting it to some other type -/// (e.g. a string) just for it to be converted back to `SocketAddr` in constructor methods -/// is pointless. -/// -/// Some examples: -/// -/// ```rust,no_run -/// # #![feature(old_io, core, convert)] -/// # #![allow(unused_must_use)] -/// -/// use std::old_io::{TcpStream, TcpListener}; -/// use std::old_io::net::udp::UdpSocket; -/// use std::old_io::net::ip::{Ipv4Addr, SocketAddr}; -/// -/// fn main() { -/// // The following lines are equivalent modulo possible "localhost" name resolution -/// // differences -/// let tcp_s = TcpStream::connect(SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 12345 }); -/// let tcp_s = TcpStream::connect((Ipv4Addr(127, 0, 0, 1), 12345)); -/// let tcp_s = TcpStream::connect(("127.0.0.1", 12345)); -/// let tcp_s = TcpStream::connect(("localhost", 12345)); -/// let tcp_s = TcpStream::connect("127.0.0.1:12345"); -/// let tcp_s = TcpStream::connect("localhost:12345"); -/// -/// // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to() behave similarly -/// let tcp_l = TcpListener::bind("localhost:12345"); -/// -/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451)).unwrap(); -/// udp_s.send_to([7, 7, 7].as_ref(), (Ipv4Addr(127, 0, 0, 1), 23451)); -/// } -/// ``` -pub trait ToSocketAddr { - /// Converts this object to single socket address value. - /// - /// If more than one value is available, this method returns the first one. If no - /// values are available, this method returns an `IoError`. - /// - /// By default this method delegates to `to_socket_addr_all` method, taking the first - /// item from its result. - fn to_socket_addr(&self) -> IoResult { - self.to_socket_addr_all() - .and_then(|v| v.into_iter().next().ok_or_else(|| IoError { - kind: old_io::InvalidInput, - desc: "no address available", - detail: None - })) - } - - /// Converts this object to all available socket address values. - /// - /// Some values like host name string naturally correspond to multiple IP addresses. - /// This method tries to return all available addresses corresponding to this object. - /// - /// By default this method delegates to `to_socket_addr` method, creating a singleton - /// vector from its result. - #[inline] - fn to_socket_addr_all(&self) -> IoResult> { - self.to_socket_addr().map(|a| vec![a]) - } -} - -impl ToSocketAddr for SocketAddr { - #[inline] - fn to_socket_addr(&self) -> IoResult { Ok(*self) } -} - -impl ToSocketAddr for (IpAddr, u16) { - #[inline] - fn to_socket_addr(&self) -> IoResult { - let (ip, port) = *self; - Ok(SocketAddr { ip: ip, port: port }) - } -} - -fn resolve_socket_addr(s: &str, p: u16) -> IoResult> { - net::get_host_addresses(s) - .map(|v| v.into_iter().map(|a| SocketAddr { ip: a, port: p }).collect()) -} - -fn parse_and_resolve_socket_addr(s: &str) -> IoResult> { - macro_rules! try_opt { - ($e:expr, $msg:expr) => ( - match $e { - Some(r) => r, - None => return Err(IoError { - kind: old_io::InvalidInput, - desc: $msg, - detail: None - }) - } - ) - } - - // split the string by ':' and convert the second part to u16 - let mut parts_iter = s.rsplitn(2, ':'); - let port_str = try_opt!(parts_iter.next(), "invalid socket address"); - let host = try_opt!(parts_iter.next(), "invalid socket address"); - let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); - resolve_socket_addr(host, port) -} - -impl<'a> ToSocketAddr for (&'a str, u16) { - fn to_socket_addr_all(&self) -> IoResult> { - let (host, port) = *self; - - // try to parse the host as a regular IpAddr first - match host.parse().ok() { - Some(addr) => return Ok(vec![SocketAddr { - ip: addr, - port: port - }]), - None => {} - } - - resolve_socket_addr(host, port) - } -} - -// accepts strings like 'localhost:12345' -impl<'a> ToSocketAddr for &'a str { - fn to_socket_addr(&self) -> IoResult { - // try to parse as a regular SocketAddr first - match self.parse().ok() { - Some(addr) => return Ok(addr), - None => {} - } - - parse_and_resolve_socket_addr(*self) - .and_then(|v| v.into_iter().next() - .ok_or_else(|| IoError { - kind: old_io::InvalidInput, - desc: "no address available", - detail: None - }) - ) - } - - fn to_socket_addr_all(&self) -> IoResult> { - // try to parse as a regular SocketAddr first - match self.parse().ok() { - Some(addr) => return Ok(vec![addr]), - None => {} - } - - parse_and_resolve_socket_addr(*self) - } -} - - -#[cfg(test)] -mod test { - use prelude::v1::*; - use super::*; - use str::FromStr; - - #[test] - fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!(Ok(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - "2a02:6b8::11:11".parse()); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), - "::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - "::FFFF:192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse()); - assert_eq!(Ok(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse()); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_socket_addr() { - assert_eq!(Ok(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), - "77.88.21.11:80".parse()); - assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), - "[2a02:6b8:0:1::1]:53".parse()); - assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), - "[::127.0.0.1]:22".parse()); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn ipv6_addr_to_string() { - let a1 = Ipv6Addr(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert!(a1.to_string() == "::ffff:192.0.2.128" || - a1.to_string() == "::FFFF:192.0.2.128"); - assert_eq!(Ipv6Addr(8, 9, 10, 11, 12, 13, 14, 15).to_string(), - "8:9:a:b:c:d:e:f"); - } - - #[test] - fn to_socket_addr_socketaddr() { - let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 12345 }; - assert_eq!(Ok(a), a.to_socket_addr()); - assert_eq!(Ok(vec![a]), a.to_socket_addr_all()); - } - - #[test] - fn to_socket_addr_ipaddr_u16() { - let a = Ipv4Addr(77, 88, 21, 11); - let p = 12345; - let e = SocketAddr { ip: a, port: p }; - assert_eq!(Ok(e), (a, p).to_socket_addr()); - assert_eq!(Ok(vec![e]), (a, p).to_socket_addr_all()); - } - - #[test] - fn to_socket_addr_str_u16() { - let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 }; - assert_eq!(Ok(a), ("77.88.21.11", 24352).to_socket_addr()); - assert_eq!(Ok(vec![a]), ("77.88.21.11", 24352).to_socket_addr_all()); - - let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }; - assert_eq!(Ok(a), ("2a02:6b8:0:1::1", 53).to_socket_addr()); - assert_eq!(Ok(vec![a]), ("2a02:6b8:0:1::1", 53).to_socket_addr_all()); - - let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 }; - assert!(("localhost", 23924).to_socket_addr_all().unwrap().contains(&a)); - } - - #[test] - fn to_socket_addr_str() { - let a = SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 24352 }; - assert_eq!(Ok(a), "77.88.21.11:24352".to_socket_addr()); - assert_eq!(Ok(vec![a]), "77.88.21.11:24352".to_socket_addr_all()); - - let a = SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }; - assert_eq!(Ok(a), "[2a02:6b8:0:1::1]:53".to_socket_addr()); - assert_eq!(Ok(vec![a]), "[2a02:6b8:0:1::1]:53".to_socket_addr_all()); - - let a = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 23924 }; - assert!("localhost:23924".to_socket_addr_all().unwrap().contains(&a)); - } -} diff --git a/src/libstd/old_io/net/mod.rs b/src/libstd/old_io/net/mod.rs deleted file mode 100644 index a3567290b0..0000000000 --- a/src/libstd/old_io/net/mod.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2013 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. - -//! Networking I/O - -#![deprecated(since = "1.0.0", - reason = "replaced with new I/O primitives in `std::net`")] -#![unstable(feature = "old_io")] - -use old_io::{IoError, IoResult, InvalidInput}; -use ops::FnMut; -use option::Option::None; -use result::Result::{Ok, Err}; -use self::ip::{SocketAddr, ToSocketAddr}; - -pub use self::addrinfo::get_host_addresses; - -pub mod addrinfo; -pub mod tcp; -pub mod udp; -pub mod ip; -pub mod pipe; - -fn with_addresses(addr: A, mut action: F) -> IoResult where - A: ToSocketAddr, - F: FnMut(SocketAddr) -> IoResult, -{ - const DEFAULT_ERROR: IoError = IoError { - kind: InvalidInput, - desc: "no addresses found for hostname", - detail: None - }; - - let addresses = try!(addr.to_socket_addr_all()); - let mut err = DEFAULT_ERROR; - for addr in addresses { - match action(addr) { - Ok(r) => return Ok(r), - Err(e) => err = e - } - } - Err(err) -} diff --git a/src/libstd/old_io/net/pipe.rs b/src/libstd/old_io/net/pipe.rs deleted file mode 100644 index 3a071e832a..0000000000 --- a/src/libstd/old_io/net/pipe.rs +++ /dev/null @@ -1,883 +0,0 @@ -// Copyright 2013 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. - -//! Named pipes -//! -//! This module contains the ability to communicate over named pipes with -//! synchronous I/O. On windows, this corresponds to talking over a Named Pipe, -//! while on Unix it corresponds to UNIX domain sockets. -//! -//! These pipes are similar to TCP in the sense that you can have both a stream to a -//! server and a server itself. The server provided accepts other `UnixStream` -//! instances as clients. - -#![allow(missing_docs)] -#![deprecated(since = "1.0.0", - reason = "will be removed to be reintroduced at a later date; \ - in the meantime consider using the `unix_socket` crate \ - for unix sockets; there is currently no replacement \ - for named pipes")] -#![unstable(feature = "old_io")] - -use prelude::v1::*; - -use ffi::CString; -use old_path::BytesContainer; -use old_io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; -use old_io::{Reader, Writer}; -use sys::pipe::UnixAcceptor as UnixAcceptorImp; -use sys::pipe::UnixListener as UnixListenerImp; -use sys::pipe::UnixStream as UnixStreamImp; -use time::Duration; - -use sys_common; - -/// A stream which communicates over a named pipe. -pub struct UnixStream { - inner: UnixStreamImp, -} - -impl UnixStream { - - /// Connect to a pipe named by `path`. This will attempt to open a - /// connection to the underlying socket. - /// - /// The returned stream will be closed when the object falls out of scope. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, old_path, io)] - /// # #![allow(unused_must_use)] - /// use std::old_io::net::pipe::UnixStream; - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let server = Path::new("path/to/my/socket"); - /// let mut stream = UnixStream::connect(&server); - /// stream.write(&[1, 2, 3]); - /// ``` - pub fn connect(path: P) -> IoResult { - let path = try!(CString::new(path.container_as_bytes())); - UnixStreamImp::connect(&path, None) - .map(|inner| UnixStream { inner: inner }) - } - - /// Connect to a pipe named by `path`, timing out if the specified number of - /// milliseconds. - /// - /// This function is similar to `connect`, except that if `timeout` - /// elapses the function will return an error of kind `TimedOut`. - /// - /// If a `timeout` with zero or negative duration is specified then - /// the function returns `Err`, with the error kind set to `TimedOut`. - #[unstable(feature = "io", - reason = "the timeout argument is likely to change types")] - pub fn connect_timeout

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsInner, - K: BytesContainer + Eq + Hash, V: BytesContainer - { - use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; - - mod rustrt { - extern { - pub fn rust_unset_sigprocmask(); - } - } - - unsafe fn set_cloexec(fd: c_int) { - let ret = c::ioctl(fd, c::FIOCLEX); - assert_eq!(ret, 0); - } - - #[cfg(all(target_os = "android", target_arch = "aarch64"))] - unsafe fn getdtablesize() -> c_int { - libc::sysconf(libc::consts::os::sysconf::_SC_OPEN_MAX) as c_int - } - #[cfg(not(all(target_os = "android", target_arch = "aarch64")))] - unsafe fn getdtablesize() -> c_int { - libc::funcs::bsd44::getdtablesize() - } - - let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null()); - - // temporary until unboxed closures land - let cfg = unsafe { - mem::transmute::<&ProcessConfig,&'static ProcessConfig>(cfg) - }; - - with_envp(cfg.env(), move|envp: *const c_void| { - with_argv(cfg.program(), cfg.args(), move|argv: *const *const libc::c_char| unsafe { - let (input, mut output) = try!(sys::os::pipe()); - - // We may use this in the child, so perform allocations before the - // fork - let devnull = b"/dev/null\0"; - - set_cloexec(output.fd()); - - let pid = fork(); - if pid < 0 { - return Err(super::last_error()) - } else if pid > 0 { - #[inline] - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 - } - - let p = Process{ pid: pid }; - drop(output); - let mut bytes = [0; 8]; - return match input.read(&mut bytes) { - Ok(8) => { - assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), - "Validation on the CLOEXEC pipe failed: {:?}", bytes); - let errno = combine(&bytes[0.. 4]); - assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); - Err(super::decode_error(errno)) - } - Err(ref e) if e.kind == EndOfFile => Ok(p), - Err(e) => { - assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) - }, - Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(p.wait(0).is_ok(), "wait(0) should either return Ok or panic"); - panic!("short read on the CLOEXEC pipe") - } - }; - } - - // And at this point we've reached a special time in the life of the - // child. The child must now be considered hamstrung and unable to - // do anything other than syscalls really. Consider the following - // scenario: - // - // 1. Thread A of process 1 grabs the malloc() mutex - // 2. Thread B of process 1 forks(), creating thread C - // 3. Thread C of process 2 then attempts to malloc() - // 4. The memory of process 2 is the same as the memory of - // process 1, so the mutex is locked. - // - // This situation looks a lot like deadlock, right? It turns out - // that this is what pthread_atfork() takes care of, which is - // presumably implemented across platforms. The first thing that - // threads to *before* forking is to do things like grab the malloc - // mutex, and then after the fork they unlock it. - // - // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but - // all collected backtraces point at malloc/free traffic in the - // child spawned process. - // - // For this reason, the block of code below should contain 0 - // invocations of either malloc of free (or their related friends). - // - // As an example of not having malloc/free traffic, we don't close - // this file descriptor by dropping the FileDesc (which contains an - // allocation). Instead we just close it manually. This will never - // have the drop glue anyway because this code never returns (the - // child will either exec() or invoke libc::exit) - let _ = libc::close(input.fd()); - - fn fail(output: &mut FileDesc) -> ! { - let errno = sys::os::errno() as u32; - let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, - CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], - CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] - ]; - // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(output.write(&bytes).is_ok()); - unsafe { libc::_exit(1) } - } - - rustrt::rust_unset_sigprocmask(); - - // If a stdio file descriptor is set to be ignored (via a -1 file - // descriptor), then we don't actually close it, but rather open - // up /dev/null into that file descriptor. Otherwise, the first file - // descriptor opened up in the child would be numbered as one of the - // stdio file descriptors, which is likely to wreak havoc. - let setup = |src: Option

, dst: c_int| { - let src = match src { - None => { - let flags = if dst == libc::STDIN_FILENO { - libc::O_RDONLY - } else { - libc::O_RDWR - }; - libc::open(devnull.as_ptr() as *const _, flags, 0) - } - Some(obj) => { - let fd = obj.as_inner().fd(); - // Leak the memory and the file descriptor. We're in the - // child now an all our resources are going to be - // cleaned up very soon - mem::forget(obj); - fd - } - }; - src != -1 && retry(|| dup2(src, dst)) != -1 - }; - - if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) } - if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) } - if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) } - - // close all other fds - for fd in (3..getdtablesize()).rev() { - if fd != output.fd() { - let _ = close(fd as c_int); - } - } - - match cfg.gid() { - Some(u) => { - if libc::setgid(u as libc::gid_t) != 0 { - fail(&mut output); - } - } - None => {} - } - match cfg.uid() { - Some(u) => { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - extern { - fn setgroups(ngroups: libc::c_int, - ptr: *const libc::c_void) -> libc::c_int; - } - let _ = setgroups(0, ptr::null()); - - if libc::setuid(u as libc::uid_t) != 0 { - fail(&mut output); - } - } - None => {} - } - if cfg.detach() { - // Don't check the error of setsid because it fails if we're the - // process leader already. We just forked so it shouldn't return - // error, but ignore it anyway. - let _ = libc::setsid(); - } - if !dirp.is_null() && chdir(dirp) == -1 { - fail(&mut output); - } - if !envp.is_null() { - *sys::os::environ() = envp as *const _; - } - let _ = execvp(*argv, argv as *mut _); - fail(&mut output); - }) - }) - } - - pub fn wait(&self, deadline: u64) -> IoResult { - use cmp; - use sync::mpsc::TryRecvError; - - static mut WRITE_FD: libc::c_int = 0; - - let mut status = 0 as c_int; - if deadline == 0 { - return match retry(|| unsafe { c::waitpid(self.pid, &mut status, 0) }) { - -1 => panic!("unknown waitpid error: {:?}", super::last_error()), - _ => Ok(translate_status(status)), - } - } - - // On unix, wait() and its friends have no timeout parameters, so there is - // no way to time out a thread in wait(). From some googling and some - // thinking, it appears that there are a few ways to handle timeouts in - // wait(), but the only real reasonable one for a multi-threaded program is - // to listen for SIGCHLD. - // - // With this in mind, the waiting mechanism with a timeout barely uses - // waitpid() at all. There are a few times that waitpid() is invoked with - // WNOHANG, but otherwise all the necessary blocking is done by waiting for - // a SIGCHLD to arrive (and that blocking has a timeout). Note, however, - // that waitpid() is still used to actually reap the child. - // - // Signal handling is super tricky in general, and this is no exception. Due - // to the async nature of SIGCHLD, we use the self-pipe trick to transmit - // data out of the signal handler to the rest of the application. The first - // idea would be to have each thread waiting with a timeout to read this - // output file descriptor, but a write() is akin to a signal(), not a - // broadcast(), so it would only wake up one thread, and possibly the wrong - // thread. Hence a helper thread is used. - // - // The helper thread here is responsible for farming requests for a - // waitpid() with a timeout, and then processing all of the wait requests. - // By guaranteeing that only this helper thread is reading half of the - // self-pipe, we're sure that we'll never lose a SIGCHLD. This helper thread - // is also responsible for select() to wait for incoming messages or - // incoming SIGCHLD messages, along with passing an appropriate timeout to - // select() to wake things up as necessary. - // - // The ordering of the following statements is also very purposeful. First, - // we must be guaranteed that the helper thread is booted and available to - // receive SIGCHLD signals, and then we must also ensure that we do a - // nonblocking waitpid() at least once before we go ask the sigchld helper. - // This prevents the race where the child exits, we boot the helper, and - // then we ask for the child's exit status (never seeing a sigchld). - // - // The actual communication between the helper thread and this thread is - // quite simple, just a channel moving data around. - - HELPER.boot(register_sigchld, waitpid_helper); - - match self.try_wait() { - Some(ret) => return Ok(ret), - None => {} - } - - let (tx, rx) = channel(); - HELPER.send(NewChild(self.pid, tx, deadline)); - return match rx.recv() { - Ok(e) => Ok(e), - Err(..) => Err(timeout("wait timed out")), - }; - - // Register a new SIGCHLD handler, returning the reading half of the - // self-pipe plus the old handler registered (return value of sigaction). - // - // Be sure to set up the self-pipe first because as soon as we register a - // handler we're going to start receiving signals. - fn register_sigchld() -> (libc::c_int, c::sigaction) { - unsafe { - let mut pipes = [0; 2]; - assert_eq!(libc::pipe(pipes.as_mut_ptr()), 0); - set_nonblocking(pipes[0], true); - set_nonblocking(pipes[1], true); - WRITE_FD = pipes[1]; - - let mut old: c::sigaction = mem::zeroed(); - let mut new: c::sigaction = mem::zeroed(); - new.sa_handler = sigchld_handler; - new.sa_flags = c::SA_NOCLDSTOP; - assert_eq!(c::sigaction(c::SIGCHLD, &new, &mut old), 0); - (pipes[0], old) - } - } - - // Helper thread for processing SIGCHLD messages - fn waitpid_helper(input: libc::c_int, - messages: Receiver, - (read_fd, old): (libc::c_int, c::sigaction)) { - set_nonblocking(input, true); - let mut set: c::fd_set = unsafe { mem::zeroed() }; - let mut tv: libc::timeval; - let mut active = Vec::<(libc::pid_t, Sender, u64)>::new(); - let max = cmp::max(input, read_fd) + 1; - - 'outer: loop { - // Figure out the timeout of our syscall-to-happen. If we're waiting - // for some processes, then they'll have a timeout, otherwise we - // wait indefinitely for a message to arrive. - // - // FIXME: sure would be nice to not have to scan the entire array - let min = active.iter().map(|a| a.2).enumerate().min_by(|p| { - p.1 - }); - let (p, idx) = match min { - Some((idx, deadline)) => { - let now = sys::timer::now(); - let ms = if now < deadline {deadline - now} else {0}; - tv = ms_to_timeval(ms); - (&mut tv as *mut _, idx) - } - None => (ptr::null_mut(), -1), - }; - - // Wait for something to happen - c::fd_set(&mut set, input); - c::fd_set(&mut set, read_fd); - match unsafe { c::select(max, &mut set, ptr::null_mut(), - ptr::null_mut(), p) } { - // interrupted, retry - -1 if os::errno() == libc::EINTR as i32 => continue, - - // We read something, break out and process - 1 | 2 => {} - - // Timeout, the pending request is removed - 0 => { - drop(active.remove(idx)); - continue - } - - n => panic!("error in select {:?} ({:?})", os::errno(), n), - } - - // Process any pending messages - if drain(input) { - loop { - match messages.try_recv() { - Ok(NewChild(pid, tx, deadline)) => { - active.push((pid, tx, deadline)); - } - // Once we've been disconnected it means the main - // thread is exiting (at_exit has run). We could - // still have active waiter for other threads, so - // we're just going to drop them all on the floor. - // This means that they won't receive a "you're - // done" message in which case they'll be considered - // as timed out, but more generally errors will - // start propagating. - Err(TryRecvError::Disconnected) => { - break 'outer; - } - Err(TryRecvError::Empty) => break, - } - } - } - - // If a child exited (somehow received SIGCHLD), then poll all - // children to see if any of them exited. - // - // We also attempt to be responsible netizens when dealing with - // SIGCHLD by invoking any previous SIGCHLD handler instead of just - // ignoring any previous SIGCHLD handler. Note that we don't provide - // a 1:1 mapping of our handler invocations to the previous handler - // invocations because we drain the `read_fd` entirely. This is - // probably OK because the kernel is already allowed to coalesce - // simultaneous signals, we're just doing some extra coalescing. - // - // Another point of note is that this likely runs the signal handler - // on a different thread than the one that received the signal. I - // *think* this is ok at this time. - // - // The main reason for doing this is to allow stdtest to run native - // tests as well. Both libgreen and libnative are running around - // with process timeouts, but libgreen should get there first - // (currently libuv doesn't handle old signal handlers). - if drain(read_fd) { - let i: usize = unsafe { mem::transmute(old.sa_handler) }; - if i != 0 { - assert!(old.sa_flags & c::SA_SIGINFO == 0); - (old.sa_handler)(c::SIGCHLD); - } - - // FIXME: sure would be nice to not have to scan the entire - // array... - active.retain(|&(pid, ref tx, _)| { - let pr = Process { pid: pid }; - match pr.try_wait() { - Some(msg) => { tx.send(msg).unwrap(); false } - None => true, - } - }); - } - } - - // Once this helper thread is done, we re-register the old sigchld - // handler and close our intermediate file descriptors. - unsafe { - assert_eq!(c::sigaction(c::SIGCHLD, &old, ptr::null_mut()), 0); - let _ = libc::close(read_fd); - let _ = libc::close(WRITE_FD); - WRITE_FD = -1; - } - } - - // Drain all pending data from the file descriptor, returning if any data - // could be drained. This requires that the file descriptor is in - // nonblocking mode. - fn drain(fd: libc::c_int) -> bool { - let mut ret = false; - loop { - let mut buf = [0u8; 1]; - match unsafe { - libc::read(fd, buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as libc::size_t) - } { - n if n > 0 => { ret = true; } - 0 => return true, - -1 if wouldblock() => return ret, - n => panic!("bad read {} ({})", - io::Error::last_os_error(), n), - } - } - } - - // Signal handler for SIGCHLD signals, must be async-signal-safe! - // - // This function will write to the writing half of the "self pipe" to wake - // up the helper thread if it's waiting. Note that this write must be - // nonblocking because if it blocks and the reader is the thread we - // interrupted, then we'll deadlock. - // - // When writing, if the write returns EWOULDBLOCK then we choose to ignore - // it. At that point we're guaranteed that there's something in the pipe - // which will wake up the other end at some point, so we just allow this - // signal to be coalesced with the pending signals on the pipe. - extern fn sigchld_handler(_signum: libc::c_int) { - let msg = 1; - match unsafe { - libc::write(WRITE_FD, &msg as *const _ as *const libc::c_void, 1) - } { - 1 => {} - -1 if wouldblock() => {} // see above comments - n => panic!("bad error on write fd: {:?} {:?}", n, os::errno()), - } - } - } - - pub fn try_wait(&self) -> Option { - let mut status = 0 as c_int; - match retry(|| unsafe { - c::waitpid(self.pid, &mut status, c::WNOHANG) - }) { - n if n == self.pid => Some(translate_status(status)), - 0 => None, - n => panic!("unknown waitpid error `{:?}`: {:?}", n, - super::last_error()), - } - } -} - -fn with_argv(prog: &CString, args: &[CString], - cb: F) - -> T - where F : FnOnce(*const *const libc::c_char) -> T -{ - let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1); - - // Convert the CStrings into an array of pointers. Note: the - // lifetime of the various CStrings involved is guaranteed to be - // larger than the lifetime of our invocation of cb, but this is - // technically unsafe as the callback could leak these pointers - // out of our scope. - ptrs.push(prog.as_ptr()); - ptrs.extend(args.iter().map(|tmp| tmp.as_ptr())); - - // Add a terminating null pointer (required by libc). - ptrs.push(ptr::null()); - - cb(ptrs.as_ptr()) -} - -fn with_envp(env: Option<&HashMap>, - cb: F) - -> T - where F : FnOnce(*const c_void) -> T, - K : BytesContainer + Eq + Hash, - V : BytesContainer -{ - // On posixy systems we can pass a char** for envp, which is a - // null-terminated array of "k=v\0" strings. Since we must create - // these strings locally, yet expose a raw pointer to them, we - // create a temporary vector to own the CStrings that outlives the - // call to cb. - match env { - Some(env) => { - let mut tmps = Vec::with_capacity(env.len()); - - for pair in env { - let mut kv = Vec::new(); - kv.push_all(pair.0.container_as_bytes()); - kv.push('=' as u8); - kv.push_all(pair.1.container_as_bytes()); - kv.push(0); // terminating null - tmps.push(kv); - } - - // As with `with_argv`, this is unsafe, since cb could leak the pointers. - let mut ptrs: Vec<*const libc::c_char> = - tmps.iter() - .map(|tmp| tmp.as_ptr() as *const libc::c_char) - .collect(); - ptrs.push(ptr::null()); - - cb(ptrs.as_ptr() as *const c_void) - } - _ => cb(ptr::null()) - } -} - -fn translate_status(status: c_int) -> ProcessExit { - #![allow(non_snake_case)] - #[cfg(any(target_os = "linux", target_os = "android"))] - mod imp { - pub fn WIFEXITED(status: i32) -> bool { (status & 0xff) == 0 } - pub fn WEXITSTATUS(status: i32) -> i32 { (status >> 8) & 0xff } - pub fn WTERMSIG(status: i32) -> i32 { status & 0x7f } - } - - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd"))] - mod imp { - pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } - pub fn WEXITSTATUS(status: i32) -> i32 { status >> 8 } - pub fn WTERMSIG(status: i32) -> i32 { status & 0o177 } - } - - if imp::WIFEXITED(status) { - ExitStatus(imp::WEXITSTATUS(status) as isize) - } else { - ExitSignal(imp::WTERMSIG(status) as isize) - } -} diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index c2a8b26aef..4e7c4d241f 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -13,14 +13,14 @@ use os::unix::prelude::*; use collections::HashMap; use env; -use ffi::{OsString, OsStr, CString}; +use ffi::{OsString, OsStr, CString, CStr}; use fmt; use io::{self, Error, ErrorKind}; use libc::{self, pid_t, c_void, c_int, gid_t, uid_t}; -use mem; use ptr; use sys::pipe2::AnonPipe; -use sys::{self, retry, c, cvt}; +use sys::{self, c, cvt, cvt_r}; +use sys::fs2::{File, OpenOptions}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -119,6 +119,12 @@ pub struct Process { pid: pid_t } +pub enum Stdio { + Inherit, + Piped(AnonPipe), + None, +} + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; impl Process { @@ -128,244 +134,208 @@ impl Process { } pub fn spawn(cfg: &Command, - in_fd: Option, out_fd: Option, err_fd: Option) - -> io::Result - { - use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; - - mod rustrt { - extern { - pub fn rust_unset_sigprocmask(); + in_fd: Stdio, + out_fd: Stdio, + err_fd: Stdio) -> io::Result { + let dirp = cfg.cwd.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null()); + + let (envp, _a, _b) = make_envp(cfg.env.as_ref()); + let (argv, _a) = make_argv(&cfg.program, &cfg.args); + let (input, output) = try!(sys::pipe2::anon_pipe()); + + let pid = unsafe { + match libc::fork() { + 0 => { + drop(input); + Process::child_after_fork(cfg, output, argv, envp, dirp, + in_fd, out_fd, err_fd) + } + n if n < 0 => return Err(Error::last_os_error()), + n => n, + } + }; + + let p = Process{ pid: pid }; + drop(output); + let mut bytes = [0; 8]; + + // loop to handle EINTR + loop { + match input.read(&mut bytes) { + Ok(0) => return Ok(p), + Ok(8) => { + assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), + "Validation on the CLOEXEC pipe failed: {:?}", bytes); + let errno = combine(&bytes[0.. 4]); + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + return Err(Error::from_raw_os_error(errno)) + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => { + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("the CLOEXEC pipe failed: {:?}", e) + }, + Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } } } - unsafe fn set_cloexec(fd: c_int) { - let ret = c::ioctl(fd, c::FIOCLEX); - assert_eq!(ret, 0); - } + fn combine(arr: &[u8]) -> i32 { + let a = arr[0] as u32; + let b = arr[1] as u32; + let c = arr[2] as u32; + let d = arr[3] as u32; - #[cfg(all(target_os = "android", target_arch = "aarch64"))] - unsafe fn getdtablesize() -> c_int { - libc::sysconf(libc::consts::os::sysconf::_SC_OPEN_MAX) as c_int + ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 } + } - #[cfg(not(all(target_os = "android", target_arch = "aarch64")))] - unsafe fn getdtablesize() -> c_int { - libc::funcs::bsd44::getdtablesize() + // And at this point we've reached a special time in the life of the + // child. The child must now be considered hamstrung and unable to + // do anything other than syscalls really. Consider the following + // scenario: + // + // 1. Thread A of process 1 grabs the malloc() mutex + // 2. Thread B of process 1 forks(), creating thread C + // 3. Thread C of process 2 then attempts to malloc() + // 4. The memory of process 2 is the same as the memory of + // process 1, so the mutex is locked. + // + // This situation looks a lot like deadlock, right? It turns out + // that this is what pthread_atfork() takes care of, which is + // presumably implemented across platforms. The first thing that + // threads to *before* forking is to do things like grab the malloc + // mutex, and then after the fork they unlock it. + // + // Despite this information, libnative's spawn has been witnessed to + // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // all collected backtraces point at malloc/free traffic in the + // child spawned process. + // + // For this reason, the block of code below should contain 0 + // invocations of either malloc of free (or their related friends). + // + // As an example of not having malloc/free traffic, we don't close + // this file descriptor by dropping the FileDesc (which contains an + // allocation). Instead we just close it manually. This will never + // have the drop glue anyway because this code never returns (the + // child will either exec() or invoke libc::exit) + unsafe fn child_after_fork(cfg: &Command, + mut output: AnonPipe, + argv: *const *const libc::c_char, + envp: *const libc::c_void, + dirp: *const libc::c_char, + in_fd: Stdio, + out_fd: Stdio, + err_fd: Stdio) -> ! { + fn fail(output: &mut AnonPipe) -> ! { + let errno = sys::os::errno() as u32; + let bytes = [ + (errno >> 24) as u8, + (errno >> 16) as u8, + (errno >> 8) as u8, + (errno >> 0) as u8, + CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], + CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] + ]; + // pipe I/O up to PIPE_BUF bytes should be atomic, and then we want + // to be sure we *don't* run at_exit destructors as we're being torn + // down regardless + assert!(output.write(&bytes).is_ok()); + unsafe { libc::_exit(1) } } - let dirp = cfg.cwd.as_ref().map(|c| c.as_ptr()).unwrap_or(ptr::null()); - - with_envp(cfg.env.as_ref(), |envp: *const c_void| { - with_argv(&cfg.program, &cfg.args, |argv: *const *const libc::c_char| unsafe { - let (input, mut output) = try!(sys::pipe2::anon_pipe()); - - // We may use this in the child, so perform allocations before the - // fork - let devnull = b"/dev/null\0"; - - set_cloexec(output.raw()); - - let pid = fork(); - if pid < 0 { - return Err(Error::last_os_error()) - } else if pid > 0 { - #[inline] - fn combine(arr: &[u8]) -> i32 { - let a = arr[0] as u32; - let b = arr[1] as u32; - let c = arr[2] as u32; - let d = arr[3] as u32; - - ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 - } - - let p = Process{ pid: pid }; - drop(output); - let mut bytes = [0; 8]; - - // loop to handle EINTER - loop { - match input.read(&mut bytes) { - Ok(8) => { - assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), - "Validation on the CLOEXEC pipe failed: {:?}", bytes); - let errno = combine(&bytes[0.. 4]); - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - return Err(Error::from_os_error(errno)) - } - Ok(0) => return Ok(p), - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) - }, - Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(p.wait().is_ok(), - "wait() should either return Ok or panic"); - panic!("short read on the CLOEXEC pipe") - } - } + let setup = |src: Stdio, dst: c_int| { + let fd = match src { + Stdio::Inherit => return true, + Stdio::Piped(pipe) => pipe.into_fd(), + + // If a stdio file descriptor is set to be ignored, we open up + // /dev/null into that file descriptor. Otherwise, the first + // file descriptor opened up in the child would be numbered as + // one of the stdio file descriptors, which is likely to wreak + // havoc. + Stdio::None => { + let mut opts = OpenOptions::new(); + opts.read(dst == libc::STDIN_FILENO); + opts.write(dst != libc::STDIN_FILENO); + let devnull = CStr::from_ptr(b"/dev/null\0".as_ptr() + as *const _); + if let Ok(f) = File::open_c(devnull, &opts) { + f.into_fd() + } else { + return false } } + }; + cvt_r(|| libc::dup2(fd.raw(), dst)).is_ok() + }; - // And at this point we've reached a special time in the life of the - // child. The child must now be considered hamstrung and unable to - // do anything other than syscalls really. Consider the following - // scenario: - // - // 1. Thread A of process 1 grabs the malloc() mutex - // 2. Thread B of process 1 forks(), creating thread C - // 3. Thread C of process 2 then attempts to malloc() - // 4. The memory of process 2 is the same as the memory of - // process 1, so the mutex is locked. - // - // This situation looks a lot like deadlock, right? It turns out - // that this is what pthread_atfork() takes care of, which is - // presumably implemented across platforms. The first thing that - // threads to *before* forking is to do things like grab the malloc - // mutex, and then after the fork they unlock it. - // - // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but - // all collected backtraces point at malloc/free traffic in the - // child spawned process. - // - // For this reason, the block of code below should contain 0 - // invocations of either malloc of free (or their related friends). - // - // As an example of not having malloc/free traffic, we don't close - // this file descriptor by dropping the FileDesc (which contains an - // allocation). Instead we just close it manually. This will never - // have the drop glue anyway because this code never returns (the - // child will either exec() or invoke libc::exit) - let _ = libc::close(input.raw()); - - fn fail(output: &mut AnonPipe) -> ! { - let errno = sys::os::errno() as u32; - let bytes = [ - (errno >> 24) as u8, - (errno >> 16) as u8, - (errno >> 8) as u8, - (errno >> 0) as u8, - CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1], - CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3] - ]; - // pipe I/O up to PIPE_BUF bytes should be atomic - assert!(output.write(&bytes).is_ok()); - unsafe { libc::_exit(1) } - } - - rustrt::rust_unset_sigprocmask(); - - // If a stdio file descriptor is set to be ignored, we don't - // actually close it, but rather open up /dev/null into that - // file descriptor. Otherwise, the first file descriptor opened - // up in the child would be numbered as one of the stdio file - // descriptors, which is likely to wreak havoc. - let setup = |src: Option, dst: c_int| { - let src = match src { - None => { - let flags = if dst == libc::STDIN_FILENO { - libc::O_RDONLY - } else { - libc::O_RDWR - }; - libc::open(devnull.as_ptr() as *const _, flags, 0) - } - Some(obj) => { - let fd = obj.raw(); - // Leak the memory and the file descriptor. We're in the - // child now an all our resources are going to be - // cleaned up very soon - mem::forget(obj); - fd - } - }; - src != -1 && retry(|| dup2(src, dst)) != -1 - }; - - if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) } - if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) } - if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) } - - // close all other fds - for fd in (3..getdtablesize()).rev() { - if fd != output.raw() { - let _ = close(fd as c_int); - } - } + if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) } + if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) } + if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) } - match cfg.gid { - Some(u) => { - if libc::setgid(u as libc::gid_t) != 0 { - fail(&mut output); - } - } - None => {} - } - match cfg.uid { - Some(u) => { - // When dropping privileges from root, the `setgroups` call - // will remove any extraneous groups. If we don't call this, - // then even though our uid has dropped, we may still have - // groups that enable us to do super-user things. This will - // fail if we aren't root, so don't bother checking the - // return value, this is just done as an optimistic - // privilege dropping function. - extern { - fn setgroups(ngroups: libc::c_int, - ptr: *const libc::c_void) -> libc::c_int; - } - let _ = setgroups(0, ptr::null()); - - if libc::setuid(u as libc::uid_t) != 0 { - fail(&mut output); - } - } - None => {} - } - if cfg.detach { - // Don't check the error of setsid because it fails if we're the - // process leader already. We just forked so it shouldn't return - // error, but ignore it anyway. - let _ = libc::setsid(); - } - if !dirp.is_null() && chdir(dirp) == -1 { - fail(&mut output); - } - if !envp.is_null() { - *sys::os::environ() = envp as *const _; - } - let _ = execvp(*argv, argv as *mut _); + if let Some(u) = cfg.gid { + if libc::setgid(u as libc::gid_t) != 0 { fail(&mut output); - }) - }) + } + } + if let Some(u) = cfg.uid { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. + let _ = c::setgroups(0, ptr::null()); + + if libc::setuid(u as libc::uid_t) != 0 { + fail(&mut output); + } + } + if cfg.detach { + // Don't check the error of setsid because it fails if we're the + // process leader already. We just forked so it shouldn't return + // error, but ignore it anyway. + let _ = libc::setsid(); + } + if !dirp.is_null() && libc::chdir(dirp) == -1 { + fail(&mut output); + } + if !envp.is_null() { + *sys::os::environ() = envp as *const _; + } + let _ = libc::execvp(*argv, argv as *mut _); + fail(&mut output) } pub fn wait(&self) -> io::Result { let mut status = 0 as c_int; - try!(cvt(retry(|| unsafe { c::waitpid(self.pid, &mut status, 0) }))); + try!(cvt_r(|| unsafe { c::waitpid(self.pid, &mut status, 0) })); Ok(translate_status(status)) } pub fn try_wait(&self) -> Option { let mut status = 0 as c_int; - match retry(|| unsafe { + match cvt_r(|| unsafe { c::waitpid(self.pid, &mut status, c::WNOHANG) }) { - n if n == self.pid => Some(translate_status(status)), - 0 => None, - n => panic!("unknown waitpid error `{:?}`: {:?}", n, - super::last_error()), + Ok(0) => None, + Ok(n) if n == self.pid => Some(translate_status(status)), + Ok(n) => panic!("unkown pid: {}", n), + Err(e) => panic!("unknown waitpid error: {}", e), } } } -fn with_argv(prog: &CString, args: &[CString], cb: F) -> T - where F : FnOnce(*const *const libc::c_char) -> T +fn make_argv(prog: &CString, args: &[CString]) + -> (*const *const libc::c_char, Vec<*const libc::c_char>) { let mut ptrs: Vec<*const libc::c_char> = Vec::with_capacity(args.len()+1); @@ -380,40 +350,38 @@ fn with_argv(prog: &CString, args: &[CString], cb: F) -> T // Add a terminating null pointer (required by libc). ptrs.push(ptr::null()); - cb(ptrs.as_ptr()) + (ptrs.as_ptr(), ptrs) } -fn with_envp(env: Option<&HashMap>, cb: F) -> T - where F : FnOnce(*const c_void) -> T +fn make_envp(env: Option<&HashMap>) + -> (*const c_void, Vec>, Vec<*const libc::c_char>) { // On posixy systems we can pass a char** for envp, which is a // null-terminated array of "k=v\0" strings. Since we must create // these strings locally, yet expose a raw pointer to them, we // create a temporary vector to own the CStrings that outlives the // call to cb. - match env { - Some(env) => { - let mut tmps = Vec::with_capacity(env.len()); - - for pair in env { - let mut kv = Vec::new(); - kv.push_all(pair.0.as_bytes()); - kv.push('=' as u8); - kv.push_all(pair.1.as_bytes()); - kv.push(0); // terminating null - tmps.push(kv); - } + if let Some(env) = env { + let mut tmps = Vec::with_capacity(env.len()); + + for pair in env { + let mut kv = Vec::new(); + kv.push_all(pair.0.as_bytes()); + kv.push('=' as u8); + kv.push_all(pair.1.as_bytes()); + kv.push(0); // terminating null + tmps.push(kv); + } - // As with `with_argv`, this is unsafe, since cb could leak the pointers. - let mut ptrs: Vec<*const libc::c_char> = - tmps.iter() - .map(|tmp| tmp.as_ptr() as *const libc::c_char) - .collect(); - ptrs.push(ptr::null()); + let mut ptrs: Vec<*const libc::c_char> = + tmps.iter() + .map(|tmp| tmp.as_ptr() as *const libc::c_char) + .collect(); + ptrs.push(ptr::null()); - cb(ptrs.as_ptr() as *const c_void) - } - _ => cb(ptr::null()) + (ptrs.as_ptr() as *const _, tmps, ptrs) + } else { + (0 as *const _, Vec::new(), Vec::new()) } } diff --git a/src/libstd/sys/unix/sync.rs b/src/libstd/sys/unix/sync.rs index 3c05fd602b..41e1e206a4 100644 --- a/src/libstd/sys/unix/sync.rs +++ b/src/libstd/sys/unix/sync.rs @@ -12,17 +12,25 @@ use libc; -pub use self::os::{PTHREAD_MUTEX_INITIALIZER, pthread_mutex_t}; +pub use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_RECURSIVE, pthread_mutex_t, + pthread_mutexattr_t}; pub use self::os::{PTHREAD_COND_INITIALIZER, pthread_cond_t}; pub use self::os::{PTHREAD_RWLOCK_INITIALIZER, pthread_rwlock_t}; extern { // mutexes + pub fn pthread_mutex_init(lock: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) + -> libc::c_int; pub fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int; pub fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int; + pub fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> libc::c_int; + pub fn pthread_mutexattr_destroy(attr: *mut pthread_mutexattr_t) -> libc::c_int; + pub fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, _type: libc::c_int) + -> libc::c_int; + // cvars pub fn pthread_cond_wait(cond: *mut pthread_cond_t, lock: *mut pthread_mutex_t) -> libc::c_int; @@ -52,12 +60,14 @@ mod os { use libc; pub type pthread_mutex_t = *mut libc::c_void; + pub type pthread_mutexattr_t = *mut libc::c_void; pub type pthread_cond_t = *mut libc::c_void; pub type pthread_rwlock_t = *mut libc::c_void; pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = 0 as *mut _; pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = 0 as *mut _; pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = 0 as *mut _; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2; } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -95,6 +105,12 @@ mod os { __opaque: [u8; __PTHREAD_MUTEX_SIZE__], } #[repr(C)] + pub struct pthread_mutexattr_t { + __sig: libc::c_long, + // note, that this is 16 bytes just to be safe, the actual struct might be smaller. + __opaque: [u8; 16], + } + #[repr(C)] pub struct pthread_cond_t { __sig: libc::c_long, __opaque: [u8; __PTHREAD_COND_SIZE__], @@ -117,6 +133,8 @@ mod os { __sig: _PTHREAD_RWLOCK_SIG_INIT, __opaque: [0; __PTHREAD_RWLOCK_SIZE__], }; + + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2; } #[cfg(target_os = "linux")] @@ -161,6 +179,12 @@ mod os { size: [u8; __SIZEOF_PTHREAD_MUTEX_T], } #[repr(C)] + pub struct pthread_mutexattr_t { + __align: libc::c_longlong, + // note, that this is 16 bytes just to be safe, the actual struct might be smaller. + size: [u8; 16], + } + #[repr(C)] pub struct pthread_cond_t { __align: libc::c_longlong, size: [u8; __SIZEOF_PTHREAD_COND_T], @@ -183,6 +207,7 @@ mod os { __align: 0, size: [0; __SIZEOF_PTHREAD_RWLOCK_T], }; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1; } #[cfg(target_os = "android")] mod os { @@ -190,6 +215,7 @@ mod os { #[repr(C)] pub struct pthread_mutex_t { value: libc::c_int } + pub type pthread_mutexattr_t = libc::c_long; #[repr(C)] pub struct pthread_cond_t { value: libc::c_int } #[repr(C)] @@ -218,4 +244,5 @@ mod os { pendingWriters: 0, reserved: [0 as *mut _; 4], }; + pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1; } diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs deleted file mode 100644 index a9f2198208..0000000000 --- a/src/libstd/sys/unix/tcp.rs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2014 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. - -#![allow(deprecated)] - -use prelude::v1::*; - -use old_io::net::ip; -use old_io::IoResult; -use libc; -use mem; -use ptr; -use super::{last_error, last_net_error, retry, sock_t}; -use sync::Arc; -use sync::atomic::{AtomicBool, Ordering}; -use sys::fs::FileDesc; -use sys::{set_nonblocking, wouldblock}; -use sys; -use sys_common; -use sys_common::net; -use sys_common::net::SocketStatus::Readable; - -pub use sys_common::net::TcpStream; - -//////////////////////////////////////////////////////////////////////////////// -// TCP listeners -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpListener { - pub inner: FileDesc, -} - -unsafe impl Sync for TcpListener {} - -impl TcpListener { - pub fn bind(addr: ip::SocketAddr) -> IoResult { - let fd = try!(net::socket(addr, libc::SOCK_STREAM)); - let ret = TcpListener { inner: FileDesc::new(fd, true) }; - - let mut storage = unsafe { mem::zeroed() }; - let len = net::addr_to_sockaddr(addr, &mut storage); - let addrp = &storage as *const _ as *const libc::sockaddr; - - // On platforms with Berkeley-derived sockets, this allows - // to quickly rebind a socket, without needing to wait for - // the OS to clean up the previous one. - try!(net::setsockopt(fd, libc::SOL_SOCKET, - libc::SO_REUSEADDR, - 1 as libc::c_int)); - - - match unsafe { libc::bind(fd, addrp, len) } { - -1 => Err(last_error()), - _ => Ok(ret), - } - } - - pub fn fd(&self) -> sock_t { self.inner.fd() } - - pub fn listen(self, backlog: isize) -> IoResult { - match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { - -1 => Err(last_net_error()), - _ => { - let (reader, writer) = try!(unsafe { sys::os::pipe() }); - set_nonblocking(reader.fd(), true); - set_nonblocking(writer.fd(), true); - set_nonblocking(self.fd(), true); - Ok(TcpAcceptor { - inner: Arc::new(AcceptorInner { - listener: self, - reader: reader, - writer: writer, - closed: AtomicBool::new(false), - }), - deadline: 0, - }) - } - } - } - - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.fd(), libc::getsockname) - } -} - -pub struct TcpAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: TcpListener, - reader: FileDesc, - writer: FileDesc, - closed: AtomicBool, -} - -unsafe impl Sync for AcceptorInner {} - -impl TcpAcceptor { - pub fn fd(&self) -> sock_t { self.inner.listener.fd() } - - pub fn accept(&mut self) -> IoResult { - // In implementing accept, the two main concerns are dealing with - // close_accept() and timeouts. The unix implementation is based on a - // nonblocking accept plus a call to select(). Windows ends up having - // an entirely separate implementation than unix, which is explained - // below. - // - // To implement timeouts, all blocking is done via select() instead of - // accept() by putting the socket in non-blocking mode. Because - // select() takes a timeout argument, we just pass through the timeout - // to select(). - // - // To implement close_accept(), we have a self-pipe to ourselves which - // is passed to select() along with the socket being accepted on. The - // self-pipe is never written to unless close_accept() is called. - let deadline = if self.deadline == 0 {None} else {Some(self.deadline)}; - - while !self.inner.closed.load(Ordering::SeqCst) { - match retry(|| unsafe { - libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut()) - }) { - -1 if wouldblock() => {} - -1 => return Err(last_net_error()), - fd => return Ok(TcpStream::new(fd as sock_t)), - } - try!(net::await(&[self.fd(), self.inner.reader.fd()], - deadline, Readable)); - } - - Err(sys_common::eof()) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, Ordering::SeqCst); - let fd = FileDesc::new(self.inner.writer.fd(), false); - match fd.write(&[0]) { - Ok(..) => Ok(()), - Err(..) if wouldblock() => Ok(()), - Err(e) => Err(e), - } - } -} - -impl Clone for TcpAcceptor { - fn clone(&self) -> TcpAcceptor { - TcpAcceptor { - inner: self.inner.clone(), - deadline: 0, - } - } -} diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index eb61f21aac..73d6cd7362 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -212,7 +212,7 @@ pub unsafe fn create(stack: usize, p: Thunk) -> io::Result { assert_eq!(pthread_attr_destroy(&mut attr), 0); return if ret != 0 { - Err(io::Error::from_os_error(ret)) + Err(io::Error::from_raw_os_error(ret)) } else { mem::forget(p); // ownership passed to pthread_create Ok(native) diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs deleted file mode 100644 index 9309147b15..0000000000 --- a/src/libstd/sys/unix/timer.rs +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2013 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. - -//! Timers for non-Linux/non-Windows OSes -//! -//! This module implements timers with a worker thread, select(), and a lot of -//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate -//! part is that I'm at a loss of what else to do one these OSes. This is also -//! why Linux has a specialized timerfd implementation and windows has its own -//! implementation (they're more accurate than this one). -//! -//! The basic idea is that there is a worker thread that's communicated to via a -//! channel and a pipe, the pipe is used by the worker thread in a select() -//! syscall with a timeout. The timeout is the "next timer timeout" while the -//! channel is used to send data over to the worker thread. -//! -//! Whenever the call to select() times out, then a channel receives a message. -//! Whenever the call returns that the file descriptor has information, then the -//! channel from timers is drained, enqueuing all incoming requests. -//! -//! The actual implementation of the helper thread is a sorted array of -//! timers in terms of target firing date. The target is the absolute time at -//! which the timer should fire. Timers are then re-enqueued after a firing if -//! the repeat boolean is set. -//! -//! Naturally, all this logic of adding times and keeping track of -//! relative/absolute time is a little lossy and not quite exact. I've done the -//! best I could to reduce the amount of calls to 'now()', but there's likely -//! still inaccuracies trickling in here and there. -//! -//! One of the tricky parts of this implementation is that whenever a timer is -//! acted upon, it must cancel whatever the previous action was (if one is -//! active) in order to act like the other implementations of this timer. In -//! order to do this, the timer's inner pointer is transferred to the worker -//! thread. Whenever the timer is modified, it first takes ownership back from -//! the worker thread in order to modify the same data structure. This has the -//! side effect of "cancelling" the previous requests while allowing a -//! re-enqueuing later on. -//! -//! Note that all time units in this file are in *milliseconds*. - -#![allow(deprecated)] - -use prelude::v1::*; -use self::Req::*; - -use old_io::IoResult; -use libc; -use mem; -use sys::os; -use io; -use ptr; -use sync::atomic::{self, Ordering}; -use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; -use sys::c; -use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; - -helper_init! { static HELPER: Helper } - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - id: usize, - inner: Option>, -} - -pub struct Inner { - cb: Option>, - interval: u64, - repeat: bool, - target: u64, - id: usize, -} - -pub enum Req { - // Add a new timer to the helper thread. - NewTimer(Box), - - // Remove a timer based on its id and then send it back on the channel - // provided - RemoveTimer(usize, Sender>), -} - -// returns the current time (in milliseconds) -pub fn now() -> u64 { - unsafe { - let mut now: libc::timeval = mem::zeroed(); - assert_eq!(c::gettimeofday(&mut now, ptr::null_mut()), 0); - return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000; - } -} - -fn helper(input: libc::c_int, messages: Receiver, _: ()) { - let mut set: c::fd_set = unsafe { mem::zeroed() }; - - let fd = FileDesc::new(input, true); - let mut timeout: libc::timeval = unsafe { mem::zeroed() }; - - // active timers are those which are able to be selected upon (and it's a - // sorted list, and dead timers are those which have expired, but ownership - // hasn't yet been transferred back to the timer itself. - let mut active: Vec> = vec![]; - let mut dead = vec![]; - - // inserts a timer into an array of timers (sorted by firing time) - fn insert(t: Box, active: &mut Vec>) { - match active.iter().position(|tm| tm.target > t.target) { - Some(pos) => { active.insert(pos, t); } - None => { active.push(t); } - } - } - - // signals the first requests in the queue, possible re-enqueueing it. - fn signal(active: &mut Vec>, - dead: &mut Vec<(usize, Box)>) { - if active.is_empty() { return } - - let mut timer = active.remove(0); - let mut cb = timer.cb.take().unwrap(); - cb.call(); - if timer.repeat { - timer.cb = Some(cb); - timer.target += timer.interval; - insert(timer, active); - } else { - dead.push((timer.id, timer)); - } - } - - 'outer: loop { - let timeout = if active.len() == 0 { - // Empty array? no timeout (wait forever for the next request) - ptr::null_mut() - } else { - let now = now(); - // If this request has already expired, then signal it and go - // through another iteration - if active[0].target <= now { - signal(&mut active, &mut dead); - continue; - } - - // The actual timeout listed in the requests array is an - // absolute date, so here we translate the absolute time to a - // relative time. - let tm = active[0].target - now; - timeout.tv_sec = (tm / 1000) as libc::time_t; - timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t; - &mut timeout as *mut libc::timeval - }; - - c::fd_set(&mut set, input); - match unsafe { - c::select(input + 1, &mut set, ptr::null_mut(), - ptr::null_mut(), timeout) - } { - // timed out - 0 => signal(&mut active, &mut dead), - - // file descriptor write woke us up, we've got some new requests - 1 => { - loop { - match messages.try_recv() { - // Once we've been disconnected it means the main thread - // is exiting (at_exit has run). We could still have - // active timers for other threads, so we're just going - // to drop them all on the floor. This is all we can - // really do, however, to prevent resource leakage. The - // remaining timers will likely start panicking quickly - // as they attempt to re-use this thread but are - // disallowed to do so. - Err(TryRecvError::Disconnected) => { - break 'outer; - } - - Ok(NewTimer(timer)) => insert(timer, &mut active), - - Ok(RemoveTimer(id, ack)) => { - match dead.iter().position(|&(i, _)| id == i) { - Some(i) => { - let (_, i) = dead.remove(i); - ack.send(i).unwrap(); - continue - } - None => {} - } - let i = active.iter().position(|i| i.id == id); - let i = i.expect("no timer found"); - let t = active.remove(i); - ack.send(t).unwrap(); - } - Err(..) => break - } - } - - // drain the file descriptor - let mut buf = [0]; - assert_eq!(fd.read(&mut buf).unwrap(), 1); - } - - -1 if os::errno() == libc::EINTR as i32 => {} - n => panic!("helper thread failed in select() with error: {} ({})", - n, io::Error::last_os_error()) - } - } -} - -impl Timer { - pub fn new() -> IoResult { - // See notes above regarding using isize return value - // instead of () - HELPER.boot(|| {}, helper); - - static ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT; - let id = ID.fetch_add(1, Ordering::Relaxed); - Ok(Timer { - id: id, - inner: Some(box Inner { - cb: None, - interval: 0, - target: 0, - repeat: false, - id: id, - }) - }) - } - - pub fn sleep(&mut self, ms: u64) { - let mut inner = self.inner(); - inner.cb = None; // cancel any previous request - self.inner = Some(inner); - - let mut to_sleep = libc::timespec { - tv_sec: (ms / 1000) as libc::time_t, - tv_nsec: ((ms % 1000) * 1000000) as libc::c_long, - }; - while unsafe { libc::nanosleep(&to_sleep, &mut to_sleep) } != 0 { - if os::errno() as isize != libc::EINTR as isize { - panic!("failed to sleep, but not because of EINTR?"); - } - } - } - - pub fn oneshot(&mut self, msecs: u64, cb: Box) { - let now = now(); - let mut inner = self.inner(); - - inner.repeat = false; - inner.cb = Some(cb); - inner.interval = msecs; - inner.target = now + msecs; - - HELPER.send(NewTimer(inner)); - } - - pub fn period(&mut self, msecs: u64, cb: Box) { - let now = now(); - let mut inner = self.inner(); - - inner.repeat = true; - inner.cb = Some(cb); - inner.interval = msecs; - inner.target = now + msecs; - - HELPER.send(NewTimer(inner)); - } - - fn inner(&mut self) -> Box { - match self.inner.take() { - Some(i) => i, - None => { - let (tx, rx) = channel(); - HELPER.send(RemoveTimer(self.id, tx)); - rx.recv().unwrap() - } - } - } -} - -impl Drop for Timer { - fn drop(&mut self) { - self.inner = Some(self.inner()); - } -} diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs deleted file mode 100644 index 2f6fd713bf..0000000000 --- a/src/libstd/sys/unix/tty.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2014 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. - -#![allow(deprecated)] - -use prelude::v1::*; - -use sys::fs::FileDesc; -use libc::{self, c_int, c_ulong}; -use old_io::{self, IoResult, IoError}; -use sys::c; -use sys_common; - -pub struct TTY { - pub fd: FileDesc, -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "bitrig", - target_os = "openbsd"))] -const TIOCGWINSZ: c_ulong = 0x40087468; - -#[cfg(any(target_os = "linux", target_os = "android"))] -const TIOCGWINSZ: c_ulong = 0x00005413; - -impl TTY { - pub fn new(fd: c_int) -> IoResult { - if unsafe { libc::isatty(fd) } != 0 { - Ok(TTY { fd: FileDesc::new(fd, true) }) - } else { - Err(IoError { - kind: old_io::MismatchedFileTypeForOperation, - desc: "file descriptor is not a TTY", - detail: None, - }) - } - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.fd.read(buf) - } - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.fd.write(buf) - } - pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> { - Err(sys_common::unimpl()) - } - - pub fn get_winsize(&mut self) -> IoResult<(isize, isize)> { - unsafe { - #[repr(C)] - struct winsize { - ws_row: u16, - ws_col: u16, - ws_xpixel: u16, - ws_ypixel: u16 - } - - let mut size = winsize { ws_row: 0, ws_col: 0, ws_xpixel: 0, ws_ypixel: 0 }; - if c::ioctl(self.fd.fd(), TIOCGWINSZ, &mut size) == -1 { - Err(IoError { - kind: old_io::OtherIoError, - desc: "Size of terminal could not be determined", - detail: None, - }) - } else { - Ok((size.ws_col as isize, size.ws_row as isize)) - } - } - } -} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 4804f65044..45f389f0ae 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -44,9 +44,15 @@ pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; pub const WSAESHUTDOWN: libc::c_int = 10058; +pub const WSA_FLAG_OVERLAPPED: libc::DWORD = 0x01; +pub const WSA_FLAG_NO_HANDLE_INHERIT: libc::DWORD = 0x80; pub const ERROR_NO_MORE_FILES: libc::DWORD = 18; pub const TOKEN_READ: libc::DWORD = 0x20008; +pub const FILE_FLAG_OPEN_REPARSE_POINT: libc::DWORD = 0x00200000; +pub const MAXIMUM_REPARSE_DATA_BUFFER_SIZE: usize = 16 * 1024; +pub const FSCTL_GET_REPARSE_POINT: libc::DWORD = 0x900a8; +pub const IO_REPARSE_TAG_SYMLINK: libc::DWORD = 0xa000000c; // Note that these are not actually HANDLEs, just values to pass to GetStdHandle pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD; @@ -214,6 +220,24 @@ pub struct FILE_END_OF_FILE_INFO { pub EndOfFile: libc::LARGE_INTEGER, } +#[repr(C)] +pub struct REPARSE_DATA_BUFFER { + pub ReparseTag: libc::c_uint, + pub ReparseDataLength: libc::c_ushort, + pub Reserved: libc::c_ushort, + pub rest: (), +} + +#[repr(C)] +pub struct SYMBOLIC_LINK_REPARSE_BUFFER { + pub SubstituteNameOffset: libc::c_ushort, + pub SubstituteNameLength: libc::c_ushort, + pub PrintNameOffset: libc::c_ushort, + pub PrintNameLength: libc::c_ushort, + pub Flags: libc::c_ulong, + pub PathBuffer: libc::WCHAR, +} + #[link(name = "ws2_32")] extern "system" { pub fn WSAStartup(wVersionRequested: libc::WORD, @@ -433,6 +457,18 @@ extern "system" { pub fn GetCurrentProcess() -> libc::HANDLE; pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE; pub fn ExitProcess(uExitCode: libc::c_uint) -> !; + pub fn DeviceIoControl(hDevice: libc::HANDLE, + dwIoControlCode: libc::DWORD, + lpInBuffer: libc::LPVOID, + nInBufferSize: libc::DWORD, + lpOutBuffer: libc::LPVOID, + nOutBufferSize: libc::DWORD, + lpBytesReturned: libc::LPDWORD, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; + pub fn CreatePipe(hReadPipe: libc::LPHANDLE, + hWritePipe: libc::LPHANDLE, + lpPipeAttributes: libc::LPSECURITY_ATTRIBUTES, + nSize: libc::DWORD) -> libc::BOOL; } #[link(name = "userenv")] diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs index 2dd61861bd..90548dcefb 100644 --- a/src/libstd/sys/windows/ext.rs +++ b/src/libstd/sys/windows/ext.rs @@ -24,9 +24,6 @@ pub mod io { use sys_common::{net2, AsInner, FromInner}; use sys; - #[allow(deprecated)] - use old_io; - /// Raw HANDLEs. #[stable(feature = "rust1", since = "1.0.0")] pub type RawHandle = libc::HANDLE; @@ -38,7 +35,7 @@ pub mod io { /// Extract raw handles. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawHandle { - /// Extract the raw handle, without taking any ownership. + /// Extracts the raw handle, without taking any ownership. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } @@ -47,20 +44,18 @@ pub mod io { #[unstable(feature = "from_raw_os", reason = "recent addition to the std::os::windows::io module")] pub trait FromRawHandle { - /// Construct a new I/O object from the specified raw handle. + /// Constructs a new I/O object from the specified raw handle. /// /// This function will **consume ownership** of the handle given, /// passing responsibility for closing the handle to the returned /// object. - fn from_raw_handle(handle: RawHandle) -> Self; - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for old_io::fs::File { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle() - } + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_handle(handle: RawHandle) -> Self; } #[stable(feature = "rust1", since = "1.0.0")] @@ -72,47 +67,15 @@ pub mod io { #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawHandle for fs::File { - fn from_raw_handle(handle: RawHandle) -> fs::File { + unsafe fn from_raw_handle(handle: RawHandle) -> fs::File { fs::File::from_inner(sys::fs2::File::from_inner(handle)) } } - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for old_io::pipe::PipeStream { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for old_io::net::pipe::UnixStream { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for old_io::net::pipe::UnixListener { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawHandle for old_io::net::pipe::UnixAcceptor { - fn as_raw_handle(&self) -> RawHandle { - self.as_inner().handle() - } - } - /// Extract raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { - /// Extract the underlying raw socket from this object. + /// Extracts the underlying raw socket from this object. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_socket(&self) -> RawSocket; } @@ -124,39 +87,13 @@ pub mod io { /// /// This function will **consume ownership** of the socket provided and /// it will be closed when the returned object goes out of scope. - fn from_raw_socket(sock: RawSocket) -> Self; - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for old_io::net::tcp::TcpStream { - fn as_raw_socket(&self) -> RawSocket { - self.as_inner().fd() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for old_io::net::tcp::TcpListener { - fn as_raw_socket(&self) -> RawSocket { - self.as_inner().socket() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for old_io::net::tcp::TcpAcceptor { - fn as_raw_socket(&self) -> RawSocket { - self.as_inner().socket() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawSocket for old_io::net::udp::UdpSocket { - fn as_raw_socket(&self) -> RawSocket { - self.as_inner().fd() - } + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_socket(sock: RawSocket) -> Self; } #[stable(feature = "rust1", since = "1.0.0")] @@ -180,21 +117,21 @@ pub mod io { #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawSocket for net::TcpStream { - fn from_raw_socket(sock: RawSocket) -> net::TcpStream { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpStream { let sock = sys::net::Socket::from_inner(sock); net::TcpStream::from_inner(net2::TcpStream::from_inner(sock)) } } #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawSocket for net::TcpListener { - fn from_raw_socket(sock: RawSocket) -> net::TcpListener { + unsafe fn from_raw_socket(sock: RawSocket) -> net::TcpListener { let sock = sys::net::Socket::from_inner(sock); net::TcpListener::from_inner(net2::TcpListener::from_inner(sock)) } } #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawSocket for net::UdpSocket { - fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { + unsafe fn from_raw_socket(sock: RawSocket) -> net::UdpSocket { let sock = sys::net::Socket::from_inner(sock); net::UdpSocket::from_inner(net2::UdpSocket::from_inner(sock)) } @@ -214,7 +151,7 @@ pub mod ffi { /// Windows-specific extensions to `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { - /// Create an `OsString` from a potentially ill-formed UTF-16 slice of + /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// /// This is lossless: calling `.encode_wide()` on the resulting string @@ -233,7 +170,7 @@ pub mod ffi { /// Windows-specific extensions to `OsStr`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { - /// Re-encode an `OsStr` as a wide character sequence, + /// Re-encodes an `OsStr` as a wide character sequence, /// i.e. potentially ill-formed UTF-16. /// /// This is lossless. Note that the encoding does not include a final @@ -258,25 +195,25 @@ pub mod fs { /// Windows-specific extensions to `OpenOptions` pub trait OpenOptionsExt { - /// Override the `dwDesiredAccess` argument to the call to `CreateFile` + /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` /// with the specified value. fn desired_access(&mut self, access: i32) -> &mut Self; - /// Override the `dwCreationDisposition` argument to the call to + /// Overrides the `dwCreationDisposition` argument to the call to /// `CreateFile` with the specified value. /// /// This will override any values of the standard `create` flags, for /// example. fn creation_disposition(&mut self, val: i32) -> &mut Self; - /// Override the `dwFlagsAndAttributes` argument to the call to + /// Overrides the `dwFlagsAndAttributes` argument to the call to /// `CreateFile` with the specified value. /// /// This will override any values of the standard flags on the /// `OpenOptions` structure. fn flags_and_attributes(&mut self, val: i32) -> &mut Self; - /// Override the `dwShareMode` argument to the call to `CreateFile` with + /// Overrides the `dwShareMode` argument to the call to `CreateFile` with /// the specified value. /// /// This will override any values of the standard flags on the diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs deleted file mode 100644 index 0bbb1a9e92..0000000000 --- a/src/libstd/sys/windows/fs.rs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2014 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. - -//! Blocking Windows-based file I/O - -#![allow(deprecated)] // this module itself is essentially deprecated - -use libc::{self, c_int}; - -use mem; -use ptr; -use old_io; - -use prelude::v1::*; -use sys; -use sys_common::{self, mkerr_libc}; - -use old_path::{Path, GenericPath}; -use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; -use old_io::{IoResult, IoError, FileStat, SeekStyle}; -use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; - -pub type fd_t = libc::c_int; - -pub struct FileDesc { - /// The underlying C file descriptor. - pub fd: fd_t, - - /// Whether to close the file descriptor on drop. - close_on_drop: bool, -} - -impl FileDesc { - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { fd: fd, close_on_drop: close_on_drop } - } - - pub fn read(&self, buf: &mut [u8]) -> IoResult { - let mut read = 0; - let ret = unsafe { - libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut read, - ptr::null_mut()) - }; - if ret != 0 { - Ok(read as usize) - } else { - Err(super::last_error()) - } - } - - pub fn write(&self, buf: &[u8]) -> IoResult<()> { - let mut cur = buf.as_ptr(); - let mut remaining = buf.len(); - while remaining > 0 { - let mut amt = 0; - let ret = unsafe { - libc::WriteFile(self.handle(), cur as libc::LPVOID, - remaining as libc::DWORD, &mut amt, - ptr::null_mut()) - }; - if ret != 0 { - remaining -= amt as usize; - cur = unsafe { cur.offset(amt as isize) }; - } else { - return Err(super::last_error()) - } - } - Ok(()) - } - - pub fn fd(&self) -> fd_t { self.fd } - - pub fn handle(&self) -> libc::HANDLE { - unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE } - } - - // A version of seek that takes &self so that tell can call it - // - the private seek should of course take &mut self. - fn seek_common(&self, pos: i64, style: SeekStyle) -> IoResult { - let whence = match style { - SeekSet => libc::FILE_BEGIN, - SeekEnd => libc::FILE_END, - SeekCur => libc::FILE_CURRENT, - }; - unsafe { - let mut newpos = 0; - match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) { - 0 => Err(super::last_error()), - _ => Ok(newpos as u64), - } - } - } - - pub fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult { - self.seek_common(pos, style) - } - - pub fn tell(&self) -> IoResult { - self.seek_common(0, SeekCur) - } - - pub fn fsync(&mut self) -> IoResult<()> { - super::mkerr_winbool(unsafe { - libc::FlushFileBuffers(self.handle()) - }) - } - - pub fn datasync(&mut self) -> IoResult<()> { return self.fsync(); } - - pub fn truncate(&mut self, offset: i64) -> IoResult<()> { - let orig_pos = try!(self.tell()); - let _ = try!(self.seek(offset, SeekSet)); - let ret = unsafe { - match libc::SetEndOfFile(self.handle()) { - 0 => Err(super::last_error()), - _ => Ok(()) - } - }; - let _ = self.seek(orig_pos as i64, SeekSet); - return ret; - } - - pub fn fstat(&self) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::fstat(self.fd(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - } - - #[allow(dead_code)] - pub fn unwrap(self) -> fd_t { - let fd = self.fd; - unsafe { mem::forget(self) }; - fd - } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.close_on_drop && self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, self.fd); - } - } - } -} - -pub fn to_utf16(s: &Path) -> IoResult> { - sys::to_utf16(s.as_str()) -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { - // Flags passed to open_osfhandle - let flags = match fm { - Open => 0, - Append => libc::O_APPEND, - Truncate => libc::O_TRUNC, - }; - let flags = match fa { - Read => flags | libc::O_RDONLY, - Write => flags | libc::O_WRONLY | libc::O_CREAT, - ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, - }; - let mut dwDesiredAccess = match fa { - Read => libc::FILE_GENERIC_READ, - Write => libc::FILE_GENERIC_WRITE, - ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE - }; - - // libuv has a good comment about this, but the basic idea is what we try to - // emulate unix semantics by enabling all sharing by allowing things such as - // deleting a file while it's still open. - let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE | - libc::FILE_SHARE_DELETE; - - let dwCreationDisposition = match (fm, fa) { - (Truncate, Read) => libc::TRUNCATE_EXISTING, - (Truncate, _) => libc::CREATE_ALWAYS, - (Open, Read) => libc::OPEN_EXISTING, - (Open, _) => libc::OPEN_ALWAYS, - (Append, Read) => { - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_EXISTING - } - (Append, _) => { - dwDesiredAccess &= !libc::FILE_WRITE_DATA; - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_ALWAYS - } - }; - - let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL; - // Compat with unix, this allows opening directories (see libuv) - dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS; - - let path = try!(to_utf16(path)); - let handle = unsafe { - libc::CreateFileW(path.as_ptr(), - dwDesiredAccess, - dwShareMode, - ptr::null_mut(), - dwCreationDisposition, - dwFlagsAndAttributes, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - Err(super::last_error()) - } else { - let fd = unsafe { - libc::open_osfhandle(handle as libc::intptr_t, flags) - }; - if fd < 0 { - let _ = unsafe { libc::CloseHandle(handle) }; - Err(super::last_error()) - } else { - Ok(FileDesc::new(fd, true)) - } - } -} - -pub fn mkdir(p: &Path, _mode: usize) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_winbool(unsafe { - // FIXME: turn mode into something useful? #2623 - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - }) -} - -pub fn readdir(p: &Path) -> IoResult> { - fn prune(root: &Path, dirs: Vec) -> Vec { - dirs.into_iter().filter(|path| { - path.as_vec() != b"." && path.as_vec() != b".." - }).map(|path| root.join(path)).collect() - } - - let star = p.join("*"); - let path = try!(to_utf16(&star)); - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != libc::INVALID_HANDLE_VALUE { - let mut paths = vec![]; - let mut more_files = 1 as libc::BOOL; - while more_files != 0 { - { - let filename = super::truncate_utf16_at_nul(&wfd.cFileName); - match String::from_utf16(filename) { - Ok(filename) => paths.push(Path::new(filename)), - Err(..) => { - assert!(libc::FindClose(find_handle) != 0); - return Err(IoError { - kind: old_io::InvalidInput, - desc: "path was not valid UTF-16", - detail: Some(format!("path was not valid UTF-16: {:?}", filename)), - }) - }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring - } - } - more_files = libc::FindNextFileW(find_handle, &mut wfd); - } - assert!(libc::FindClose(find_handle) != 0); - Ok(prune(p, paths)) - } else { - Err(super::last_error()) - } - } -} - -pub fn unlink(p: &Path) -> IoResult<()> { - fn do_unlink(p_utf16: &Vec) -> IoResult<()> { - super::mkerr_winbool(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) }) - } - - let p_utf16 = try!(to_utf16(p)); - let res = do_unlink(&p_utf16); - match res { - Ok(()) => Ok(()), - Err(e) => { - // FIXME: change the code below to use more direct calls - // than `stat` and `chmod`, to avoid re-conversion to - // utf16 etc. - - // On unix, a readonly file can be successfully removed. On windows, - // however, it cannot. To keep the two platforms in line with - // respect to their behavior, catch this case on windows, attempt to - // change it to read-write, and then remove the file. - if e.kind == old_io::PermissionDenied { - let stat = match stat(p) { - Ok(stat) => stat, - Err(..) => return Err(e), - }; - if stat.perm.intersects(old_io::USER_WRITE) { return Err(e) } - - match chmod(p, (stat.perm | old_io::USER_WRITE).bits() as usize) { - Ok(()) => do_unlink(&p_utf16), - Err(..) => { - // Try to put it back as we found it - let _ = chmod(p, stat.perm.bits() as usize); - Err(e) - } - } - } else { - Err(e) - } - } - } -} - -pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = try!(to_utf16(old)); - let new = try!(to_utf16(new)); - super::mkerr_winbool(unsafe { - libc::MoveFileExW(old.as_ptr(), new.as_ptr(), libc::MOVEFILE_REPLACE_EXISTING) - }) -} - -pub fn chmod(p: &Path, mode: usize) -> IoResult<()> { - let p = try!(to_utf16(p)); - mkerr_libc(unsafe { - libc::wchmod(p.as_ptr(), mode as libc::c_int) - }) -} - -pub fn rmdir(p: &Path) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_winbool(unsafe { libc::RemoveDirectoryW(p.as_ptr()) }) -} - -pub fn chown(_p: &Path, _uid: isize, _gid: isize) -> IoResult<()> { - // libuv has this as a no-op, so seems like this should as well? - Ok(()) -} - -pub fn readlink(p: &Path) -> IoResult { - // FIXME: I have a feeling that this reads intermediate symlinks as well. - use sys::c::compat::kernel32::GetFinalPathNameByHandleW; - let p = try!(to_utf16(p)); - let handle = unsafe { - libc::CreateFileW(p.as_ptr(), - libc::GENERIC_READ, - libc::FILE_SHARE_READ, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_ATTRIBUTE_NORMAL, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - // Specify (sz - 1) because the documentation states that it's the size - // without the null pointer - let ret = super::fill_utf16_buf(|buf, sz| unsafe { - GetFinalPathNameByHandleW(handle, - buf as *const u16, - sz - 1, - libc::VOLUME_NAME_DOS) - }, |data| { - Path::new(String::from_utf16(data).unwrap()) - }); - assert!(unsafe { libc::CloseHandle(handle) } != 0); - return ret; -} - -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - use sys::c::compat::kernel32::CreateSymbolicLinkW; - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL - }) -} - -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) - }) -} - -fn mkstat(stat: &libc::stat) -> FileStat { - FileStat { - size: stat.st_size as u64, - kind: match (stat.st_mode as libc::c_int) & libc::S_IFMT { - libc::S_IFREG => old_io::FileType::RegularFile, - libc::S_IFDIR => old_io::FileType::Directory, - libc::S_IFIFO => old_io::FileType::NamedPipe, - libc::S_IFBLK => old_io::FileType::BlockSpecial, - libc::S_IFLNK => old_io::FileType::Symlink, - _ => old_io::FileType::Unknown, - }, - perm: FilePermission::from_bits_truncate(stat.st_mode as u32), - created: stat.st_ctime as u64, - modified: stat.st_mtime as u64, - accessed: stat.st_atime as u64, - unstable: UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize:0, - blocks: 0, - flags: 0, - gen: 0, - }, - } -} - -pub fn stat(p: &Path) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - let p = try!(to_utf16(p)); - match unsafe { libc::wstat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -// FIXME: move this to platform-specific modules (for now)? -pub fn lstat(_p: &Path) -> IoResult { - // FIXME: implementation is missing - Err(sys_common::unimpl()) -} - -pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let mut buf = libc::utimbuf { - actime: atime as libc::time64_t, - modtime: mtime as libc::time64_t, - }; - let p = try!(to_utf16(p)); - mkerr_libc(unsafe { - libc::wutime(p.as_ptr(), &mut buf) - }) -} diff --git a/src/libstd/sys/windows/fs2.rs b/src/libstd/sys/windows/fs2.rs index d03e45649e..e66c356b7c 100644 --- a/src/libstd/sys/windows/fs2.rs +++ b/src/libstd/sys/windows/fs2.rs @@ -12,13 +12,13 @@ use core::prelude::*; use io::prelude::*; use os::windows::prelude::*; -use default::Default; -use ffi::{OsString, AsOsStr}; +use ffi::OsString; use io::{self, Error, SeekFrom}; use libc::{self, HANDLE}; use mem; use path::{Path, PathBuf}; use ptr; +use slice; use sync::Arc; use sys::handle::Handle; use sys::{c, cvt}; @@ -364,22 +364,40 @@ pub fn rmdir(p: &Path) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result { - use sys::c::compat::kernel32::GetFinalPathNameByHandleW; let mut opts = OpenOptions::new(); opts.read(true); - let file = try!(File::open(p, &opts));; - - // Specify (sz - 1) because the documentation states that it's the size - // without the null pointer - // - // FIXME: I have a feeling that this reads intermediate symlinks as well. - let ret: OsString = try!(super::fill_utf16_buf_new(|buf, sz| unsafe { - GetFinalPathNameByHandleW(file.handle.raw(), - buf as *const u16, - sz - 1, - libc::VOLUME_NAME_DOS) - }, |s| OsStringExt::from_wide(s))); - Ok(PathBuf::from(&ret)) + opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32); + let file = try!(File::open(p, &opts)); + + let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + let mut bytes = 0; + + unsafe { + try!(cvt({ + c::DeviceIoControl(file.handle.raw(), + c::FSCTL_GET_REPARSE_POINT, + 0 as *mut _, + 0, + space.as_mut_ptr() as *mut _, + space.len() as libc::DWORD, + &mut bytes, + 0 as *mut _) + })); + let buf: *const c::REPARSE_DATA_BUFFER = space.as_ptr() as *const _; + if (*buf).ReparseTag != c::IO_REPARSE_TAG_SYMLINK { + return Err(io::Error::new(io::ErrorKind::Other, "not a symlink")) + } + let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER = + &(*buf).rest as *const _ as *const _; + let path_buffer = &(*info).PathBuffer as *const _ as *const u16; + let subst_off = (*info).SubstituteNameOffset / 2; + let subst_ptr = path_buffer.offset(subst_off as isize); + let subst_len = (*info).SubstituteNameLength / 2; + let subst = slice::from_raw_parts(subst_ptr, subst_len as usize); + + Ok(PathBuf::from(OsString::from_wide(subst))) + } + } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 0089dcad45..c3a30aae9e 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -36,11 +36,34 @@ impl Handle { } pub fn read(&self, buf: &mut [u8]) -> io::Result { - read(self.0, buf) + let mut read = 0; + let res = cvt(unsafe { + libc::ReadFile(self.0, buf.as_ptr() as libc::LPVOID, + buf.len() as libc::DWORD, &mut read, + ptr::null_mut()) + }); + + match res { + Ok(_) => Ok(read as usize), + + // The special treatment of BrokenPipe is to deal with Windows + // pipe semantics, which yields this error when *reading* from + // a pipe after the other end has closed; we interpret that as + // EOF on the pipe. + Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0), + + Err(e) => Err(e) + } } pub fn write(&self, buf: &[u8]) -> io::Result { - write(self.0, buf) + let mut amt = 0; + try!(cvt(unsafe { + libc::WriteFile(self.0, buf.as_ptr() as libc::LPVOID, + buf.len() as libc::DWORD, &mut amt, + ptr::null_mut()) + })); + Ok(amt as usize) } } @@ -49,35 +72,3 @@ impl Drop for Handle { unsafe { let _ = libc::CloseHandle(self.0); } } } - - -pub fn read(h: HANDLE, buf: &mut [u8]) -> io::Result { - let mut read = 0; - let res = cvt(unsafe { - libc::ReadFile(h, buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut read, - ptr::null_mut()) - }); - - match res { - Ok(_) => Ok(read as usize), - - // The special treatment of BrokenPipe is to deal with Windows - // pipe semantics, which yields this error when *reading* from - // a pipe after the other end has closed; we interpret that as - // EOF on the pipe. - Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0), - - Err(e) => Err(e) - } -} - -pub fn write(h: HANDLE, buf: &[u8]) -> io::Result { - let mut amt = 0; - try!(cvt(unsafe { - libc::WriteFile(h, buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut amt, - ptr::null_mut()) - })); - Ok(amt as usize) -} diff --git a/src/libstd/sys/windows/helper_signal.rs b/src/libstd/sys/windows/helper_signal.rs deleted file mode 100644 index a9fb2c6822..0000000000 --- a/src/libstd/sys/windows/helper_signal.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 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 libc::{self, BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle}; -use ptr; - -pub type signal = HANDLE; - -pub fn new() -> (HANDLE, HANDLE) { - unsafe { - let handle = CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE, - ptr::null()); - (handle, handle) - } -} - -pub fn signal(handle: HANDLE) { - assert!(unsafe { SetEvent(handle) != 0 }); -} - -pub fn close(handle: HANDLE) { - assert!(unsafe { CloseHandle(handle) != 0 }); -} - -extern "system" { - fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - bInitialState: BOOL, - lpName: LPCSTR) -> HANDLE; - fn SetEvent(hEvent: HANDLE) -> BOOL; -} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index e9d5fca531..5ae5f6f201 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -17,136 +17,30 @@ use prelude::v1::*; use ffi::{OsStr, OsString}; use io::{self, ErrorKind}; use libc; -use mem; -#[allow(deprecated)] -use num::Int; -use old_io::{self, IoResult, IoError}; +use num::Zero; use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; -use sync::{Once, ONCE_INIT}; pub mod backtrace; pub mod c; pub mod condvar; pub mod ext; -pub mod fs; pub mod fs2; pub mod handle; -pub mod helper_signal; pub mod mutex; pub mod net; pub mod os; pub mod os_str; -pub mod pipe; pub mod pipe2; -pub mod process; pub mod process2; pub mod rwlock; pub mod stack_overflow; pub mod sync; -pub mod tcp; pub mod thread; pub mod thread_local; pub mod time; -pub mod timer; -pub mod tty; -pub mod udp; pub mod stdio; -pub mod addrinfo { - pub use sys_common::net::get_host_addresses; - pub use sys_common::net::get_address_name; -} - -// FIXME: move these to c module -pub type sock_t = libc::SOCKET; -pub type wrlen = libc::c_int; -pub type msglen_t = libc::c_int; -pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); } - -// windows has zero values as errors -#[allow(deprecated)] -fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { - if ret == 0 { - Err(last_error()) - } else { - Ok(()) - } -} - -#[allow(deprecated)] -pub fn last_error() -> IoError { - let errno = os::errno() as i32; - let mut err = decode_error(errno); - err.detail = Some(os::error_string(errno)); - err -} - -#[allow(deprecated)] -pub fn last_net_error() -> IoError { - let errno = unsafe { c::WSAGetLastError() as i32 }; - let mut err = decode_error(errno); - err.detail = Some(os::error_string(errno)); - err -} - -#[allow(deprecated)] -pub fn last_gai_error(_errno: i32) -> IoError { - last_net_error() -} - -/// Convert an `errno` value into a high-level error variant and description. -#[allow(deprecated)] -pub fn decode_error(errno: i32) -> IoError { - let (kind, desc) = match errno { - libc::EOF => (old_io::EndOfFile, "end of file"), - libc::ERROR_NO_DATA => (old_io::BrokenPipe, "the pipe is being closed"), - libc::ERROR_FILE_NOT_FOUND => (old_io::FileNotFound, "file not found"), - libc::ERROR_INVALID_NAME => (old_io::InvalidInput, "invalid file name"), - libc::WSAECONNREFUSED => (old_io::ConnectionRefused, "connection refused"), - libc::WSAECONNRESET => (old_io::ConnectionReset, "connection reset"), - libc::ERROR_ACCESS_DENIED | libc::WSAEACCES => - (old_io::PermissionDenied, "permission denied"), - libc::WSAEWOULDBLOCK => { - (old_io::ResourceUnavailable, "resource temporarily unavailable") - } - libc::WSAENOTCONN => (old_io::NotConnected, "not connected"), - libc::WSAECONNABORTED => (old_io::ConnectionAborted, "connection aborted"), - libc::WSAEADDRNOTAVAIL => (old_io::ConnectionRefused, "address not available"), - libc::WSAEADDRINUSE => (old_io::ConnectionRefused, "address in use"), - libc::ERROR_BROKEN_PIPE => (old_io::EndOfFile, "the pipe has ended"), - libc::ERROR_OPERATION_ABORTED => - (old_io::TimedOut, "operation timed out"), - libc::WSAEINVAL => (old_io::InvalidInput, "invalid argument"), - libc::ERROR_CALL_NOT_IMPLEMENTED => - (old_io::IoUnavailable, "function not implemented"), - libc::ERROR_INVALID_HANDLE => - (old_io::MismatchedFileTypeForOperation, - "invalid handle provided to function"), - libc::ERROR_NOTHING_TO_TERMINATE => - (old_io::InvalidInput, "no process to kill"), - libc::ERROR_ALREADY_EXISTS => - (old_io::PathAlreadyExists, "path already exists"), - - // libuv maps this error code to EISDIR. we do too. if it is found - // to be incorrect, we can add in some more machinery to only - // return this message when ERROR_INVALID_FUNCTION after certain - // Windows calls. - libc::ERROR_INVALID_FUNCTION => (old_io::InvalidInput, - "illegal operation on a directory"), - - _ => (old_io::OtherIoError, "unknown error") - }; - IoError { kind: kind, desc: desc, detail: None } -} - -#[allow(deprecated)] -pub fn decode_error_detailed(errno: i32) -> IoError { - let mut err = decode_error(errno); - err.detail = Some(os::error_string(errno)); - err -} - pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as libc::c_int { libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied, @@ -170,58 +64,6 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } - -#[inline] -pub fn retry(f: F) -> I where F: FnOnce() -> I { f() } // PR rust-lang/rust/#17020 - -pub fn ms_to_timeval(ms: u64) -> libc::timeval { - libc::timeval { - tv_sec: (ms / 1000) as libc::c_long, - tv_usec: ((ms % 1000) * 1000) as libc::c_long, - } -} - -#[allow(deprecated)] -pub fn wouldblock() -> bool { - let err = os::errno(); - err == libc::WSAEWOULDBLOCK as i32 -} - -#[allow(deprecated)] -pub fn set_nonblocking(fd: sock_t, nb: bool) { - let mut set = nb as libc::c_ulong; - if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) } != 0 { - // The above function should not return an error unless we passed it - // invalid parameters. Panic on errors. - panic!("set_nonblocking called with invalid parameters: {}", last_error()); - } -} - -pub fn init_net() { - unsafe { - static START: Once = ONCE_INIT; - - START.call_once(|| { - let mut data: c::WSADATA = mem::zeroed(); - let ret = c::WSAStartup(0x202, // version 2.2 - &mut data); - assert_eq!(ret, 0); - }); - } -} - -#[allow(deprecated)] -pub fn to_utf16(s: Option<&str>) -> IoResult> { - match s { - Some(s) => Ok(to_utf16_os(OsStr::from_str(s))), - None => Err(IoError { - kind: old_io::InvalidInput, - desc: "valid unicode input required", - detail: None, - }), - } -} - fn to_utf16_os(s: &OsStr) -> Vec { let mut v: Vec<_> = s.encode_wide().collect(); v.push(0); @@ -242,7 +84,7 @@ fn to_utf16_os(s: &OsStr) -> Vec { // Once the syscall has completed (errors bail out early) the second closure is // yielded the data which has been read from the syscall. The return value // from this closure is then the return value of the function. -fn fill_utf16_buf_base(mut f1: F1, f2: F2) -> Result +fn fill_utf16_buf(mut f1: F1, f2: F2) -> io::Result where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD, F2: FnOnce(&[u16]) -> T { @@ -274,7 +116,7 @@ fn fill_utf16_buf_base(mut f1: F1, f2: F2) -> Result c::SetLastError(0); let k = match f1(buf.as_mut_ptr(), n as libc::DWORD) { 0 if libc::GetLastError() == 0 => 0, - 0 => return Err(()), + 0 => return Err(io::Error::last_os_error()), n => n, } as usize; if k == n && libc::GetLastError() == @@ -289,21 +131,6 @@ fn fill_utf16_buf_base(mut f1: F1, f2: F2) -> Result } } -#[allow(deprecated)] -fn fill_utf16_buf(f1: F1, f2: F2) -> IoResult - where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD, - F2: FnOnce(&[u16]) -> T -{ - fill_utf16_buf_base(f1, f2).map_err(|()| IoError::last_error()) -} - -fn fill_utf16_buf_new(f1: F1, f2: F2) -> io::Result - where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD, - F2: FnOnce(&[u16]) -> T -{ - fill_utf16_buf_base(f1, f2).map_err(|()| io::Error::last_os_error()) -} - fn os2path(s: &[u16]) -> PathBuf { PathBuf::from(OsString::from_wide(s)) } @@ -316,9 +143,8 @@ pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { } } -#[allow(deprecated)] -fn cvt(i: I) -> io::Result { - if i == Int::zero() { +fn cvt(i: I) -> io::Result { + if i == I::zero() { Err(io::Error::last_os_error()) } else { Ok(i) diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 0847f3b52b..ca20858bb5 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use cell::UnsafeCell; use sys::sync as ffi; +use mem; pub struct Mutex { inner: UnsafeCell } @@ -57,3 +58,33 @@ impl Mutex { // ... } } + +pub struct ReentrantMutex { inner: Box> } + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub unsafe fn new() -> ReentrantMutex { + let mutex = ReentrantMutex { inner: box mem::uninitialized() }; + ffi::InitializeCriticalSection(mutex.inner.get()); + mutex + } + + pub unsafe fn lock(&self) { + ffi::EnterCriticalSection(self.inner.get()); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::TryEnterCriticalSection(self.inner.get()) != 0 + } + + pub unsafe fn unlock(&self) { + ffi::LeaveCriticalSection(self.inner.get()); + } + + pub unsafe fn destroy(&self) { + ffi::DeleteCriticalSection(self.inner.get()); + } +} diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index 12a8ef99d7..6bbcd96815 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -15,8 +15,8 @@ use libc::consts::os::extra::INVALID_SOCKET; use libc::{self, c_int, c_void}; use mem; use net::SocketAddr; -#[allow(deprecated)] -use num::{SignedInt, Int}; +use num::One; +use ops::Neg; use rt; use sync::{Once, ONCE_INIT}; use sys::c; @@ -43,17 +43,14 @@ pub fn init() { /// Returns the last error from the Windows socket interface. fn last_error() -> io::Error { - io::Error::from_os_error(unsafe { c::WSAGetLastError() }) + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) } /// Checks if the signed integer is the Windows constant `SOCKET_ERROR` (-1) /// and if so, returns the last error from the Windows socket interface. . This /// function must be called before another call to the socket API is made. -/// -/// FIXME: generics needed? -#[allow(deprecated)] -pub fn cvt(t: T) -> io::Result { - let one: T = Int::one(); +pub fn cvt + PartialEq>(t: T) -> io::Result { + let one: T = T::one(); if t == -one { Err(last_error()) } else { @@ -70,7 +67,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { /// Provides the functionality of `cvt` for a closure. #[allow(deprecated)] -pub fn cvt_r(mut f: F) -> io::Result where F: FnMut() -> T { +pub fn cvt_r(mut f: F) -> io::Result + where F: FnMut() -> T, T: One + Neg + PartialEq +{ cvt(f()) } @@ -80,7 +79,11 @@ impl Socket { SocketAddr::V4(..) => libc::AF_INET, SocketAddr::V6(..) => libc::AF_INET6, }; - match unsafe { libc::socket(fam, ty, 0) } { + let socket = unsafe { + c::WSASocketW(fam, ty, 0, 0 as *mut _, 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT) + }; + match socket { INVALID_SOCKET => Err(last_error()), n => Ok(Socket(n)), } @@ -103,7 +106,9 @@ impl Socket { match c::WSASocketW(info.iAddressFamily, info.iSocketType, info.iProtocol, - &mut info, 0, 0) { + &mut info, 0, + c::WSA_FLAG_OVERLAPPED | + c::WSA_FLAG_NO_HANDLE_INHERIT) { INVALID_SOCKET => Err(last_error()), n => Ok(Socket(n)), } diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index d5843a2f99..5cfc201042 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -22,15 +22,12 @@ use io; use libc::types::os::arch::extra::LPWCH; use libc::{self, c_int, c_void}; use mem; -#[allow(deprecated)] -use old_io::{IoError, IoResult}; use ops::Range; use os::windows::ffi::EncodeWide; use path::{self, PathBuf}; use ptr; use slice; use sys::c; -use sys::fs::FileDesc; use sys::handle::Handle; use libc::funcs::extra::kernel32::{ @@ -42,7 +39,7 @@ pub fn errno() -> i32 { unsafe { libc::GetLastError() as i32 } } -/// Get a detailed string description for the given error number +/// Gets a detailed string description for the given error number. pub fn error_string(errnum: i32) -> String { use libc::types::os::arch::extra::DWORD; use libc::types::os::arch::extra::LPWSTR; @@ -233,13 +230,13 @@ impl StdError for JoinPathsError { } pub fn current_exe() -> io::Result { - super::fill_utf16_buf_new(|buf, sz| unsafe { + super::fill_utf16_buf(|buf, sz| unsafe { libc::GetModuleFileNameW(ptr::null_mut(), buf, sz) }, super::os2path) } pub fn getcwd() -> io::Result { - super::fill_utf16_buf_new(|buf, sz| unsafe { + super::fill_utf16_buf(|buf, sz| unsafe { libc::GetCurrentDirectoryW(sz, buf) }, super::os2path) } @@ -259,7 +256,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { pub fn getenv(k: &OsStr) -> Option { let k = super::to_utf16_os(k); - super::fill_utf16_buf_new(|buf, sz| unsafe { + super::fill_utf16_buf(|buf, sz| unsafe { libc::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, |buf| { OsStringExt::from_wide(buf) @@ -336,27 +333,8 @@ pub fn page_size() -> usize { } } -#[allow(deprecated)] -pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { - // Windows pipes work subtly differently than unix pipes, and their - // inheritance has to be handled in a different way that I do not - // fully understand. Here we explicitly make the pipe non-inheritable, - // which means to pass it to a subprocess they need to be duplicated - // first, as in std::run. - let mut fds = [0; 2]; - match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, - (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { - 0 => { - assert!(fds[0] != -1 && fds[0] != 0); - assert!(fds[1] != -1 && fds[1] != 0); - Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) - } - _ => Err(IoError::last_error()), - } -} - pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf_new(|buf, sz| unsafe { + super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap() } @@ -371,7 +349,7 @@ pub fn home_dir() -> Option { return None } let _handle = Handle::new(token); - super::fill_utf16_buf_new(|buf, mut sz| { + super::fill_utf16_buf(|buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { 0 if libc::GetLastError() != 0 => 0, 0 => sz, diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs deleted file mode 100644 index 064c003bd1..0000000000 --- a/src/libstd/sys/windows/pipe.rs +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2014 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. - -//! Named pipes implementation for windows -//! -//! If are unfortunate enough to be reading this code, I would like to first -//! apologize. This was my first encounter with windows named pipes, and it -//! didn't exactly turn out very cleanly. If you, too, are new to named pipes, -//! read on as I'll try to explain some fun things that I ran into. -//! -//! # Unix pipes vs Named pipes -//! -//! As with everything else, named pipes on windows are pretty different from -//! unix pipes on unix. On unix, you use one "server pipe" to accept new client -//! pipes. So long as this server pipe is active, new children pipes can -//! connect. On windows, you instead have a number of "server pipes", and each -//! of these server pipes can throughout their lifetime be attached to a client -//! or not. Once attached to a client, a server pipe may then disconnect at a -//! later date. -//! -//! # Accepting clients -//! -//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces -//! are built around the unix flavors. This means that we have one "server -//! pipe" to which many clients can connect. In order to make this compatible -//! with the windows model, each connected client consumes ownership of a server -//! pipe, and then a new server pipe is created for the next client. -//! -//! Note that the server pipes attached to clients are never given back to the -//! listener for recycling. This could possibly be implemented with a channel so -//! the listener half can re-use server pipes, but for now I err'd on the simple -//! side of things. Each stream accepted by a listener will destroy the server -//! pipe after the stream is dropped. -//! -//! This model ends up having a small race or two, and you can find more details -//! on the `native_accept` method. -//! -//! # Simultaneous reads and writes -//! -//! In testing, I found that two simultaneous writes and two simultaneous reads -//! on a pipe ended up working out just fine, but problems were encountered when -//! a read was executed simultaneously with a write. After some googling around, -//! it sounded like named pipes just weren't built for this kind of interaction, -//! and the suggested solution was to use overlapped I/O. -//! -//! I don't really know what overlapped I/O is, but my basic understanding after -//! reading about it is that you have an external Event which is used to signal -//! I/O completion, passed around in some OVERLAPPED structures. As to what this -//! is, I'm not exactly sure. -//! -//! This problem implies that all named pipes are created with the -//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is -//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and -//! inside of this structure is a HANDLE from CreateEvent. After the I/O is -//! determined to be pending (may complete in the future), the -//! GetOverlappedResult function is used to block on the event, waiting for the -//! I/O to finish. -//! -//! This scheme ended up working well enough. There were two snags that I ran -//! into, however: -//! -//! * Each UnixStream instance needs its own read/write events to wait on. These -//! can't be shared among clones of the same stream because the documentation -//! states that it unsets the event when the I/O is started (would possibly -//! corrupt other events simultaneously waiting). For convenience's sake, -//! these events are lazily initialized. -//! -//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition -//! to all pipes created through `connect`. Notably this means that the -//! ConnectNamedPipe function is nonblocking, implying that the Listener needs -//! to have yet another event to do the actual blocking. -//! -//! # Conclusion -//! -//! The conclusion here is that I probably don't know the best way to work with -//! windows named pipes, but the solution here seems to work well enough to get -//! the test suite passing (the suite is in libstd), and that's good enough for -//! me! - -#![allow(deprecated)] - -use prelude::v1::*; - -use libc; -use ffi::CString; -use old_io::{self, IoError, IoResult}; -use mem; -use ptr; -use str; -use sync::atomic::{AtomicBool, Ordering}; -use sync::{Arc, Mutex}; - -use sys_common::{self, eof}; - -use super::{c, os, timer, decode_error_detailed}; - -fn to_utf16(c: &CString) -> IoResult> { - super::to_utf16(str::from_utf8(c.as_bytes()).ok()) -} - -struct Event(libc::HANDLE); - -impl Event { - fn new(manual_reset: bool, initial_state: bool) -> IoResult { - let event = unsafe { - libc::CreateEventW(ptr::null_mut(), - manual_reset as libc::BOOL, - initial_state as libc::BOOL, - ptr::null()) - }; - if event as usize == 0 { - Err(super::last_error()) - } else { - Ok(Event(event)) - } - } - - fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle } -} - -impl Drop for Event { - fn drop(&mut self) { - unsafe { let _ = libc::CloseHandle(self.handle()); } - } -} - -unsafe impl Send for Event {} -unsafe impl Sync for Event {} - -struct Inner { - handle: libc::HANDLE, - lock: Mutex<()>, - read_closed: AtomicBool, - write_closed: AtomicBool, -} - -impl Inner { - fn new(handle: libc::HANDLE) -> Inner { - Inner { - handle: handle, - lock: Mutex::new(()), - read_closed: AtomicBool::new(false), - write_closed: AtomicBool::new(false), - } - } -} - -impl Drop for Inner { - fn drop(&mut self) { - unsafe { - let _ = libc::FlushFileBuffers(self.handle); - let _ = libc::CloseHandle(self.handle); - } - } -} - -unsafe impl Send for Inner {} -unsafe impl Sync for Inner {} - -unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE { - libc::CreateNamedPipeW( - name, - libc::PIPE_ACCESS_DUPLEX | - if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} | - libc::FILE_FLAG_OVERLAPPED, - libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE | - libc::PIPE_WAIT, - libc::PIPE_UNLIMITED_INSTANCES, - 65536, - 65536, - 0, - ptr::null_mut() - ) -} - -pub fn await(handle: libc::HANDLE, deadline: u64, - events: &[libc::HANDLE]) -> IoResult { - use libc::consts::os::extra::{WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0}; - - // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo - // to figure out if we should indeed get the result. - let ms = if deadline == 0 { - libc::INFINITE as u64 - } else { - let now = timer::now(); - if deadline < now {0} else {deadline - now} - }; - let ret = unsafe { - c::WaitForMultipleObjects(events.len() as libc::DWORD, - events.as_ptr(), - libc::FALSE, - ms as libc::DWORD) - }; - match ret { - WAIT_FAILED => Err(super::last_error()), - WAIT_TIMEOUT => unsafe { - let _ = c::CancelIo(handle); - Err(sys_common::timeout("operation timed out")) - }, - n => Ok((n - WAIT_OBJECT_0) as usize) - } -} - -fn epipe() -> IoError { - IoError { - kind: old_io::EndOfFile, - desc: "the pipe has ended", - detail: None, - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixStream { - inner: Arc, - write: Option, - read: Option, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - fn try_connect(p: *const u16) -> Option { - // Note that most of this is lifted from the libuv implementation. - // The idea is that if we fail to open a pipe in read/write mode - // that we try afterwards in just read or just write - let mut result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_READ | libc::GENERIC_WRITE, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - - let err = unsafe { libc::GetLastError() }; - if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { - result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - } - let err = unsafe { libc::GetLastError() }; - if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { - result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - } - None - } - - pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr)); - let start = timer::now(); - loop { - match UnixStream::try_connect(addr.as_ptr()) { - Some(handle) => { - let inner = Inner::new(handle); - let mut mode = libc::PIPE_TYPE_BYTE | - libc::PIPE_READMODE_BYTE | - libc::PIPE_WAIT; - let ret = unsafe { - libc::SetNamedPipeHandleState(inner.handle, - &mut mode, - ptr::null_mut(), - ptr::null_mut()) - }; - return if ret == 0 { - Err(super::last_error()) - } else { - Ok(UnixStream { - inner: Arc::new(inner), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - }) - } - } - None => {} - } - - // On windows, if you fail to connect, you may need to call the - // `WaitNamedPipe` function, and this is indicated with an error - // code of ERROR_PIPE_BUSY. - let code = unsafe { libc::GetLastError() }; - if code as isize != libc::ERROR_PIPE_BUSY as isize { - return Err(super::last_error()) - } - - match timeout { - Some(timeout) => { - let now = timer::now(); - let timed_out = (now - start) >= timeout || unsafe { - let ms = (timeout - (now - start)) as libc::DWORD; - libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0 - }; - if timed_out { - return Err(sys_common::timeout("connect timed out")) - } - } - - // An example I found on Microsoft's website used 20 - // seconds, libuv uses 30 seconds, hence we make the - // obvious choice of waiting for 25 seconds. - None => { - if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 { - return Err(super::last_error()) - } - } - } - } - } - - pub fn handle(&self) -> libc::HANDLE { self.inner.handle } - - fn read_closed(&self) -> bool { - self.inner.read_closed.load(Ordering::SeqCst) - } - - fn write_closed(&self) -> bool { - self.inner.write_closed.load(Ordering::SeqCst) - } - - fn cancel_io(&self) -> IoResult<()> { - match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } { - 0 if os::errno() == libc::ERROR_NOT_FOUND as i32 => { - Ok(()) - } - 0 => Err(super::last_error()), - _ => Ok(()) - } - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.read.is_none() { - self.read = Some(try!(Event::new(true, false))); - } - - let mut bytes_read = 0; - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.read.as_ref().unwrap().handle(); - - // Pre-flight check to see if the reading half has been closed. This - // must be done before issuing the ReadFile request, but after we - // acquire the lock. - // - // See comments in close_read() about why this lock is necessary. - let guard = self.inner.lock.lock(); - if self.read_closed() { - return Err(eof()) - } - - // Issue a nonblocking requests, succeeding quickly if it happened to - // succeed. - let ret = unsafe { - libc::ReadFile(self.handle(), - buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, - &mut bytes_read, - &mut overlapped) - }; - if ret != 0 { return Ok(bytes_read as usize) } - - // If our errno doesn't say that the I/O is pending, then we hit some - // legitimate error and return immediately. - if os::errno() != libc::ERROR_IO_PENDING as i32 { - return Err(super::last_error()) - } - - // Now that we've issued a successful nonblocking request, we need to - // wait for it to finish. This can all be done outside the lock because - // we'll see any invocation of CancelIoEx. We also call this in a loop - // because we're woken up if the writing half is closed, we just need to - // realize that the reading half wasn't closed and we go right back to - // sleep. - drop(guard); - loop { - // Process a timeout if one is pending - let wait_succeeded = await(self.handle(), self.read_deadline, - &[overlapped.hEvent]); - - let ret = unsafe { - libc::GetOverlappedResult(self.handle(), - &mut overlapped, - &mut bytes_read, - libc::TRUE) - }; - // If we succeeded, or we failed for some reason other than - // CancelIoEx, return immediately - if ret != 0 { return Ok(bytes_read as usize) } - if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 { - return Err(super::last_error()) - } - - // If the reading half is now closed, then we're done. If we woke up - // because the writing half was closed, keep trying. - if wait_succeeded.is_err() { - return Err(sys_common::timeout("read timed out")) - } - if self.read_closed() { - return Err(eof()) - } - } - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - if self.write.is_none() { - self.write = Some(try!(Event::new(true, false))); - } - - let mut offset = 0; - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.write.as_ref().unwrap().handle(); - - while offset < buf.len() { - let mut bytes_written = 0; - - // This sequence below is quite similar to the one found in read(). - // Some careful looping is done to ensure that if close_write() is - // invoked we bail out early, and if close_read() is invoked we keep - // going after we woke up. - // - // See comments in close_read() about why this lock is necessary. - let guard = self.inner.lock.lock(); - if self.write_closed() { - return Err(epipe()) - } - let ret = unsafe { - libc::WriteFile(self.handle(), - buf[offset..].as_ptr() as libc::LPVOID, - (buf.len() - offset) as libc::DWORD, - &mut bytes_written, - &mut overlapped) - }; - let err = os::errno(); - drop(guard); - - if ret == 0 { - if err != libc::ERROR_IO_PENDING as i32 { - return Err(decode_error_detailed(err as i32)) - } - // Process a timeout if one is pending - let wait_succeeded = await(self.handle(), self.write_deadline, - &[overlapped.hEvent]); - let ret = unsafe { - libc::GetOverlappedResult(self.handle(), - &mut overlapped, - &mut bytes_written, - libc::TRUE) - }; - // If we weren't aborted, this was a legit error, if we were - // aborted, then check to see if the write half was actually - // closed or whether we woke up from the read half closing. - if ret == 0 { - if os::errno() != libc::ERROR_OPERATION_ABORTED as i32 { - return Err(super::last_error()) - } - if !wait_succeeded.is_ok() { - let amt = offset + bytes_written as usize; - return if amt > 0 { - Err(IoError { - kind: old_io::ShortWrite(amt), - desc: "short write during write", - detail: None, - }) - } else { - Err(sys_common::timeout("write timed out")) - } - } - if self.write_closed() { - return Err(epipe()) - } - continue // retry - } - } - offset += bytes_written as usize; - } - Ok(()) - } - - pub fn close_read(&mut self) -> IoResult<()> { - // On windows, there's no actual shutdown() method for pipes, so we're - // forced to emulate the behavior manually at the application level. To - // do this, we need to both cancel any pending requests, as well as - // prevent all future requests from succeeding. These two operations are - // not atomic with respect to one another, so we must use a lock to do - // so. - // - // The read() code looks like: - // - // 1. Make sure the pipe is still open - // 2. Submit a read request - // 3. Wait for the read request to finish - // - // The race this lock is preventing is if another thread invokes - // close_read() between steps 1 and 2. By atomically executing steps 1 - // and 2 with a lock with respect to close_read(), we're guaranteed that - // no thread will erroneously sit in a read forever. - let _guard = self.inner.lock.lock(); - self.inner.read_closed.store(true, Ordering::SeqCst); - self.cancel_io() - } - - pub fn close_write(&mut self) -> IoResult<()> { - // see comments in close_read() for why this lock is necessary - let _guard = self.inner.lock.lock(); - self.inner.write_closed.store(true, Ordering::SeqCst); - self.cancel_io() - } - - pub fn set_timeout(&mut self, timeout: Option) { - let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - self.read_deadline = deadline; - self.write_deadline = deadline; - } - pub fn set_read_timeout(&mut self, timeout: Option) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - pub fn set_write_timeout(&mut self, timeout: Option) { - self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { - UnixStream { - inner: self.inner.clone(), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Listener -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixListener { - handle: libc::HANDLE, - name: CString, -} - -unsafe impl Send for UnixListener {} -unsafe impl Sync for UnixListener {} - -impl UnixListener { - pub fn bind(addr: &CString) -> IoResult { - // Although we technically don't need the pipe until much later, we - // create the initial handle up front to test the validity of the name - // and such. - let addr_v = try!(to_utf16(addr)); - let ret = unsafe { pipe(addr_v.as_ptr(), true) }; - if ret == libc::INVALID_HANDLE_VALUE { - Err(super::last_error()) - } else { - Ok(UnixListener { handle: ret, name: addr.clone() }) - } - } - - pub fn listen(self) -> IoResult { - Ok(UnixAcceptor { - listener: self, - event: try!(Event::new(true, false)), - deadline: 0, - inner: Arc::new(AcceptorState { - abort: try!(Event::new(true, false)), - closed: AtomicBool::new(false), - }), - }) - } - - pub fn handle(&self) -> libc::HANDLE { - self.handle - } -} - -impl Drop for UnixListener { - fn drop(&mut self) { - unsafe { let _ = libc::CloseHandle(self.handle); } - } -} - -pub struct UnixAcceptor { - inner: Arc, - listener: UnixListener, - event: Event, - deadline: u64, -} - -struct AcceptorState { - abort: Event, - closed: AtomicBool, -} - -impl UnixAcceptor { - pub fn accept(&mut self) -> IoResult { - // This function has some funky implementation details when working with - // unix pipes. On windows, each server named pipe handle can be - // connected to a one or zero clients. To the best of my knowledge, a - // named server is considered active and present if there exists at - // least one server named pipe for it. - // - // The model of this function is to take the current known server - // handle, connect a client to it, and then transfer ownership to the - // UnixStream instance. The next time accept() is invoked, it'll need a - // different server handle to connect a client to. - // - // Note that there is a possible race here. Once our server pipe is - // handed off to a `UnixStream` object, the stream could be closed, - // meaning that there would be no active server pipes, hence even though - // we have a valid `UnixAcceptor`, no one can connect to it. For this - // reason, we generate the next accept call's server pipe at the end of - // this function call. - // - // This provides us an invariant that we always have at least one server - // connection open at a time, meaning that all connects to this acceptor - // should succeed while this is active. - // - // The actual implementation of doing this is a little tricky. Once a - // server pipe is created, a client can connect to it at any time. I - // assume that which server a client connects to is nondeterministic, so - // we also need to guarantee that the only server able to be connected - // to is the one that we're calling ConnectNamedPipe on. This means that - // we have to create the second server pipe *after* we've already - // accepted a connection. In order to at least somewhat gracefully - // handle errors, this means that if the second server pipe creation - // fails that we disconnect the connected client and then just keep - // using the original server pipe. - let handle = self.listener.handle; - - // If we've had an artificial call to close_accept, be sure to never - // proceed in accepting new clients in the future - if self.inner.closed.load(Ordering::SeqCst) { return Err(eof()) } - - let name = try!(to_utf16(&self.listener.name)); - - // Once we've got a "server handle", we need to wait for a client to - // connect. The ConnectNamedPipe function will block this thread until - // someone on the other end connects. This function can "fail" if a - // client connects after we created the pipe but before we got down - // here. Thanks windows. - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.event.handle(); - if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } { - let mut err = unsafe { libc::GetLastError() }; - - if err == libc::ERROR_IO_PENDING as libc::DWORD { - // Process a timeout if one is pending - let wait_succeeded = await(handle, self.deadline, - &[self.inner.abort.handle(), - overlapped.hEvent]); - - // This will block until the overlapped I/O is completed. The - // timeout was previously handled, so this will either block in - // the normal case or succeed very quickly in the timeout case. - let ret = unsafe { - let mut transfer = 0; - libc::GetOverlappedResult(handle, - &mut overlapped, - &mut transfer, - libc::TRUE) - }; - if ret == 0 { - if wait_succeeded.is_ok() { - err = unsafe { libc::GetLastError() }; - } else { - return Err(sys_common::timeout("accept timed out")) - } - } else { - // we succeeded, bypass the check below - err = libc::ERROR_PIPE_CONNECTED as libc::DWORD; - } - } - if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD { - return Err(super::last_error()) - } - } - - // Now that we've got a connected client to our handle, we need to - // create a second server pipe. If this fails, we disconnect the - // connected client and return an error (see comments above). - let new_handle = unsafe { pipe(name.as_ptr(), false) }; - if new_handle == libc::INVALID_HANDLE_VALUE { - let ret = Err(super::last_error()); - // If our disconnection fails, then there's not really a whole lot - // that we can do, so panic - let err = unsafe { libc::DisconnectNamedPipe(handle) }; - assert!(err != 0); - return ret; - } else { - self.listener.handle = new_handle; - } - - // Transfer ownership of our handle into this stream - Ok(UnixStream { - inner: Arc::new(Inner::new(handle)), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - }) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|i| i + timer::now()).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, Ordering::SeqCst); - let ret = unsafe { - c::SetEvent(self.inner.abort.handle()) - }; - if ret == 0 { - Err(super::last_error()) - } else { - Ok(()) - } - } - - pub fn handle(&self) -> libc::HANDLE { - self.listener.handle() - } -} - -impl Clone for UnixAcceptor { - fn clone(&self) -> UnixAcceptor { - let name = to_utf16(&self.listener.name).unwrap(); - UnixAcceptor { - inner: self.inner.clone(), - event: Event::new(true, false).unwrap(), - deadline: 0, - listener: UnixListener { - name: self.listener.name.clone(), - handle: unsafe { - let p = pipe(name.as_ptr(), false) ; - assert!(p != libc::INVALID_HANDLE_VALUE as libc::HANDLE); - p - }, - }, - } - } -} diff --git a/src/libstd/sys/windows/pipe2.rs b/src/libstd/sys/windows/pipe2.rs index 229481e3d5..b441d8beed 100644 --- a/src/libstd/sys/windows/pipe2.rs +++ b/src/libstd/sys/windows/pipe2.rs @@ -10,68 +10,39 @@ use prelude::v1::*; -use sys::handle; use io; -use libc::{self, c_int, HANDLE}; +use libc; +use sys::cvt; +use sys::c; +use sys::handle::Handle; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes //////////////////////////////////////////////////////////////////////////////// pub struct AnonPipe { - fd: c_int + inner: Handle, } -pub unsafe fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - // Windows pipes work subtly differently than unix pipes, and their - // inheritance has to be handled in a different way that I do not - // fully understand. Here we explicitly make the pipe non-inheritable, - // which means to pass it to a subprocess they need to be duplicated - // first, as in std::run. - let mut fds = [0; 2]; - match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, - (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { - 0 => { - assert!(fds[0] != -1 && fds[0] != 0); - assert!(fds[1] != -1 && fds[1] != 0); - - Ok((AnonPipe::from_fd(fds[0]), AnonPipe::from_fd(fds[1]))) - } - _ => Err(io::Error::last_os_error()), - } +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + let mut reader = libc::INVALID_HANDLE_VALUE; + let mut writer = libc::INVALID_HANDLE_VALUE; + try!(cvt(unsafe { + c::CreatePipe(&mut reader, &mut writer, 0 as *mut _, 0) + })); + let reader = Handle::new(reader); + let writer = Handle::new(writer); + Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer })) } impl AnonPipe { - pub fn from_fd(fd: libc::c_int) -> AnonPipe { - AnonPipe { fd: fd } - } - - pub fn raw(&self) -> HANDLE { - unsafe { libc::get_osfhandle(self.fd) as libc::HANDLE } - } + pub fn handle(&self) -> &Handle { &self.inner } pub fn read(&self, buf: &mut [u8]) -> io::Result { - handle::read(self.raw(), buf) + self.inner.read(buf) } pub fn write(&self, buf: &[u8]) -> io::Result { - handle::write(self.raw(), buf) - } -} - -impl Drop for AnonPipe { - fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, self.fd); - } - } + self.inner.write(buf) } } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs deleted file mode 100644 index b10042090d..0000000000 --- a/src/libstd/sys/windows/process.rs +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright 2012-2014 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. - -#![allow(deprecated)] // this module itself is essentially deprecated - -use prelude::v1::*; - -use collections; -use env; -use ffi::CString; -use hash::Hash; -use libc::{pid_t, c_void}; -use libc; -use mem; -#[allow(deprecated)] use old_io::fs::PathExtensions; -use old_io::process::{ProcessExit, ExitStatus}; -use old_io::{IoResult, IoError}; -use old_io; -use fs::PathExt; -use old_path::{BytesContainer, GenericPath}; -use ptr; -use str; -use sync::{StaticMutex, MUTEX_INIT}; -use sys::fs::FileDesc; -use sys::timer; -use sys_common::{AsInner, timeout}; - -pub use sys_common::ProcessConfig; - -// `CreateProcess` is racy! -// http://support.microsoft.com/kb/315939 -static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT; - -/// A value representing a child process. -/// -/// The lifetime of this value is linked to the lifetime of the actual -/// process - the Process destructor calls self.finish() which waits -/// for the process to terminate. -pub struct Process { - /// The unique id of the process (this should never be negative). - pid: pid_t, - - /// A HANDLE to the process, which will prevent the pid being - /// re-used until the handle is closed. - handle: *mut (), -} - -impl Drop for Process { - fn drop(&mut self) { - free_handle(self.handle); - } -} - -impl Process { - pub fn id(&self) -> pid_t { - self.pid - } - - pub unsafe fn kill(&self, signal: isize) -> IoResult<()> { - Process::killpid(self.pid, signal) - } - - pub unsafe fn killpid(pid: pid_t, signal: isize) -> IoResult<()> { - let handle = libc::OpenProcess(libc::PROCESS_TERMINATE | - libc::PROCESS_QUERY_INFORMATION, - libc::FALSE, pid as libc::DWORD); - if handle.is_null() { - return Err(super::last_error()) - } - let ret = match signal { - // test for existence on signal 0 - 0 => { - let mut status = 0; - let ret = libc::GetExitCodeProcess(handle, &mut status); - if ret == 0 { - Err(super::last_error()) - } else if status != libc::STILL_ACTIVE { - Err(IoError { - kind: old_io::InvalidInput, - desc: "no process to kill", - detail: None, - }) - } else { - Ok(()) - } - } - 15 | 9 => { // sigterm or sigkill - let ret = libc::TerminateProcess(handle, 1); - super::mkerr_winbool(ret) - } - _ => Err(IoError { - kind: old_io::IoUnavailable, - desc: "unsupported signal on windows", - detail: None, - }) - }; - let _ = libc::CloseHandle(handle); - return ret; - } - - #[allow(deprecated)] - pub fn spawn(cfg: &C, in_fd: Option

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsInner, - K: BytesContainer + Eq + Hash, V: BytesContainer - { - use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; - use libc::consts::os::extra::{ - TRUE, FALSE, - STARTF_USESTDHANDLES, - INVALID_HANDLE_VALUE, - DUPLICATE_SAME_ACCESS - }; - use libc::funcs::extra::kernel32::{ - GetCurrentProcess, - DuplicateHandle, - CloseHandle, - CreateProcessW - }; - use libc::funcs::extra::msvcrt::get_osfhandle; - - use mem; - - if cfg.gid().is_some() || cfg.uid().is_some() { - return Err(IoError { - kind: old_io::IoUnavailable, - desc: "unsupported gid/uid requested on windows", - detail: None, - }) - } - - // To have the spawning semantics of unix/windows stay the same, we need to - // read the *child's* PATH if one is provided. See #15149 for more details. - let program = cfg.env().and_then(|env| { - for (key, v) in env { - if b"PATH" != key.container_as_bytes() { continue } - let v = match ::str::from_utf8(v.container_as_bytes()) { - Ok(s) => s, - Err(..) => continue, - }; - - // Split the value and test each path to see if the - // program exists. - for path in ::env::split_paths(v) { - let program = str::from_utf8(cfg.program().as_bytes()).unwrap(); - let path = path.join(program) - .with_extension(env::consts::EXE_EXTENSION); - if path.exists() { - return Some(CString::new(path.to_str().unwrap()).unwrap()) - } - } - break - } - None - }); - - unsafe { - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::() as DWORD; - si.dwFlags = STARTF_USESTDHANDLES; - - let cur_proc = GetCurrentProcess(); - - // Similarly to unix, we don't actually leave holes for the stdio file - // descriptors, but rather open up /dev/null equivalents. These - // equivalents are drawn from libuv's windows process spawning. - let set_fd = |fd: &Option

, slot: &mut HANDLE, - is_stdin: bool| { - match *fd { - None => { - let access = if is_stdin { - libc::FILE_GENERIC_READ - } else { - libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES - }; - let size = mem::size_of::(); - let mut sa = libc::SECURITY_ATTRIBUTES { - nLength: size as libc::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut filename: Vec = "NUL".utf16_units().collect(); - filename.push(0); - *slot = libc::CreateFileW(filename.as_ptr(), - access, - libc::FILE_SHARE_READ | - libc::FILE_SHARE_WRITE, - &mut sa, - libc::OPEN_EXISTING, - 0, - ptr::null_mut()); - if *slot == INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - } - Some(ref fd) => { - let orig = get_osfhandle(fd.as_inner().fd()) as HANDLE; - if orig == INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - if DuplicateHandle(cur_proc, orig, cur_proc, slot, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - return Err(super::last_error()) - } - } - } - Ok(()) - }; - - try!(set_fd(&in_fd, &mut si.hStdInput, true)); - try!(set_fd(&out_fd, &mut si.hStdOutput, false)); - try!(set_fd(&err_fd, &mut si.hStdError, false)); - - let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()), - cfg.args()); - let mut pi = zeroed_process_information(); - let mut create_err = None; - - // stolen from the libuv code. - let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; - if cfg.detach() { - flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; - } - - with_envp(cfg.env(), |envp| { - with_dirp(cfg.cwd(), |dirp| { - let mut cmd_str: Vec = cmd_str.utf16_units().collect(); - cmd_str.push(0); - let _lock = CREATE_PROCESS_LOCK.lock().unwrap(); - let created = CreateProcessW(ptr::null(), - cmd_str.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - TRUE, - flags, envp, dirp, - &mut si, &mut pi); - if created == FALSE { - create_err = Some(super::last_error()); - } - }) - }); - - assert!(CloseHandle(si.hStdInput) != 0); - assert!(CloseHandle(si.hStdOutput) != 0); - assert!(CloseHandle(si.hStdError) != 0); - - match create_err { - Some(err) => return Err(err), - None => {} - } - - // We close the thread handle because we don't care about keeping the - // thread id valid, and we aren't keeping the thread handle around to be - // able to close it later. We don't close the process handle however - // because std::we want the process id to stay valid at least until the - // calling code closes the process handle. - assert!(CloseHandle(pi.hThread) != 0); - - Ok(Process { - pid: pi.dwProcessId as pid_t, - handle: pi.hProcess as *mut () - }) - } - } - - /// Waits for a process to exit and returns the exit code, failing - /// if there is no process with the specified id. - /// - /// Note that this is private to avoid race conditions on unix where if - /// a user calls waitpid(some_process.get_id()) then some_process.finish() - /// and some_process.destroy() and some_process.finalize() will then either - /// operate on a none-existent process or, even worse, on a newer process - /// with the same id. - pub fn wait(&self, deadline: u64) -> IoResult { - use libc::types::os::arch::extra::DWORD; - use libc::consts::os::extra::{ - SYNCHRONIZE, - PROCESS_QUERY_INFORMATION, - FALSE, - STILL_ACTIVE, - INFINITE, - WAIT_TIMEOUT, - WAIT_OBJECT_0, - }; - use libc::funcs::extra::kernel32::{ - OpenProcess, - GetExitCodeProcess, - CloseHandle, - WaitForSingleObject, - }; - - unsafe { - let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, - FALSE, - self.pid as DWORD); - if process.is_null() { - return Err(super::last_error()) - } - - loop { - let mut status = 0; - if GetExitCodeProcess(process, &mut status) == FALSE { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err; - } - if status != STILL_ACTIVE { - assert!(CloseHandle(process) != 0); - return Ok(ExitStatus(status as isize)); - } - let interval = if deadline == 0 { - INFINITE - } else { - let now = timer::now(); - if deadline < now {0} else {(deadline - now) as u32} - }; - match WaitForSingleObject(process, interval) { - WAIT_OBJECT_0 => {} - WAIT_TIMEOUT => { - assert!(CloseHandle(process) != 0); - return Err(timeout("process wait timed out")) - } - _ => { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err - } - } - } - } - } -} - -fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { - libc::types::os::arch::extra::STARTUPINFO { - cb: 0, - lpReserved: ptr::null_mut(), - lpDesktop: ptr::null_mut(), - lpTitle: ptr::null_mut(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::null_mut(), - hStdInput: libc::INVALID_HANDLE_VALUE, - hStdOutput: libc::INVALID_HANDLE_VALUE, - hStdError: libc::INVALID_HANDLE_VALUE, - } -} - -fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { - libc::types::os::arch::extra::PROCESS_INFORMATION { - hProcess: ptr::null_mut(), - hThread: ptr::null_mut(), - dwProcessId: 0, - dwThreadId: 0 - } -} - -fn make_command_line(prog: &CString, args: &[CString]) -> String { - let mut cmd = String::new(); - append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() - .expect("expected program name to be utf-8 encoded")); - for arg in args { - cmd.push(' '); - append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() - .expect("expected argument to be utf-8 encoded")); - } - return cmd; - - fn append_arg(cmd: &mut String, arg: &str) { - // If an argument has 0 characters then we need to quote it to ensure - // that it actually gets passed through on the command line or otherwise - // it will be dropped entirely when parsed on the other end. - let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0; - if quote { - cmd.push('"'); - } - let argvec: Vec = arg.chars().collect(); - for i in 0..argvec.len() { - append_char_at(cmd, &argvec, i); - } - if quote { - cmd.push('"'); - } - } - - fn append_char_at(cmd: &mut String, arg: &[char], i: usize) { - match arg[i] { - '"' => { - // Escape quotes. - cmd.push_str("\\\""); - } - '\\' => { - if backslash_run_ends_in_quote(arg, i) { - // Double all backslashes that are in runs before quotes. - cmd.push_str("\\\\"); - } else { - // Pass other backslashes through unescaped. - cmd.push('\\'); - } - } - c => { - cmd.push(c); - } - } - } - - fn backslash_run_ends_in_quote(s: &[char], mut i: usize) -> bool { - while i < s.len() && s[i] == '\\' { - i += 1; - } - return i < s.len() && s[i] == '"'; - } -} - -fn with_envp(env: Option<&collections::HashMap>, cb: F) -> T - where K: BytesContainer + Eq + Hash, - V: BytesContainer, - F: FnOnce(*mut c_void) -> T, -{ - // On Windows we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - match env { - Some(env) => { - let mut blk = Vec::new(); - - for pair in env { - let kv = format!("{}={}", - pair.0.container_as_str().unwrap(), - pair.1.container_as_str().unwrap()); - blk.extend(kv.utf16_units()); - blk.push(0); - } - - blk.push(0); - - cb(blk.as_mut_ptr() as *mut c_void) - } - _ => cb(ptr::null_mut()) - } -} - -fn with_dirp(d: Option<&CString>, cb: F) -> T where - F: FnOnce(*const u16) -> T, -{ - match d { - Some(dir) => { - let dir_str = str::from_utf8(dir.as_bytes()).ok() - .expect("expected workingdirectory to be utf-8 encoded"); - let mut dir_str: Vec = dir_str.utf16_units().collect(); - dir_str.push(0); - cb(dir_str.as_ptr()) - }, - None => cb(ptr::null()) - } -} - -fn free_handle(handle: *mut ()) { - assert!(unsafe { - libc::CloseHandle(mem::transmute(handle)) != 0 - }) -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use str; - use ffi::CString; - use super::make_command_line; - - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - make_command_line(&CString::new(prog).unwrap(), - &args.iter() - .map(|a| CString::new(*a).unwrap()) - .collect::>()) - } - - assert_eq!( - test_wrapper("prog", &["aaa", "bbb", "ccc"]), - "prog aaa bbb ccc" - ); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!( - test_wrapper("echo", &["a b c"]), - "echo \"a b c\"" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}" - ); - } -} diff --git a/src/libstd/sys/windows/process2.rs b/src/libstd/sys/windows/process2.rs index 7e832b6384..5ddcf3d1ea 100644 --- a/src/libstd/sys/windows/process2.rs +++ b/src/libstd/sys/windows/process2.rs @@ -105,11 +105,18 @@ pub struct Process { handle: Handle, } +pub enum Stdio { + Inherit, + Piped(AnonPipe), + None, +} + impl Process { #[allow(deprecated)] pub fn spawn(cfg: &Command, - in_fd: Option, out_fd: Option, err_fd: Option) - -> io::Result + in_fd: Stdio, + out_fd: Stdio, + err_fd: Stdio) -> io::Result { use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; use libc::consts::os::extra::{ @@ -133,7 +140,7 @@ impl Process { // read the *child's* PATH if one is provided. See #15149 for more details. let program = cfg.env.as_ref().and_then(|env| { for (key, v) in env { - if OsStr::from_str("PATH") != &**key { continue } + if OsStr::new("PATH") != &**key { continue } // Split the value and test each path to see if the // program exists. @@ -156,13 +163,16 @@ impl Process { let cur_proc = GetCurrentProcess(); - // Similarly to unix, we don't actually leave holes for the stdio file - // descriptors, but rather open up /dev/null equivalents. These - // equivalents are drawn from libuv's windows process spawning. - let set_fd = |fd: &Option, slot: &mut HANDLE, + let set_fd = |fd: &Stdio, slot: &mut HANDLE, is_stdin: bool| { match *fd { - None => { + Stdio::Inherit => {} + + // Similarly to unix, we don't actually leave holes for the + // stdio file descriptors, but rather open up /dev/null + // equivalents. These equivalents are drawn from libuv's + // windows process spawning. + Stdio::None => { let access = if is_stdin { libc::FILE_GENERIC_READ } else { @@ -188,11 +198,8 @@ impl Process { return Err(Error::last_os_error()) } } - Some(ref pipe) => { - let orig = pipe.raw(); - if orig == INVALID_HANDLE_VALUE { - return Err(Error::last_os_error()) - } + Stdio::Piped(ref pipe) => { + let orig = pipe.handle().raw(); if DuplicateHandle(cur_proc, orig, cur_proc, slot, 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { return Err(Error::last_os_error()) @@ -235,9 +242,15 @@ impl Process { }) }); - assert!(CloseHandle(si.hStdInput) != 0); - assert!(CloseHandle(si.hStdOutput) != 0); - assert!(CloseHandle(si.hStdError) != 0); + if !in_fd.inherited() { + assert!(CloseHandle(si.hStdInput) != 0); + } + if !out_fd.inherited() { + assert!(CloseHandle(si.hStdOutput) != 0); + } + if !err_fd.inherited() { + assert!(CloseHandle(si.hStdError) != 0); + } match create_err { Some(err) => return Err(err), @@ -296,6 +309,12 @@ impl Process { } } +impl Stdio { + fn inherited(&self) -> bool { + match *self { Stdio::Inherit => true, _ => false } + } +} + #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitStatus(i32); @@ -362,7 +381,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> Vec { // it will be dropped entirely when parsed on the other end. let arg_bytes = &arg.as_inner().inner.as_inner(); let quote = arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') - || arg_bytes.len() == 0; + || arg_bytes.is_empty(); if quote { cmd.push('"' as u16); } @@ -444,7 +463,7 @@ mod tests { fn test_make_command_line() { fn test_wrapper(prog: &str, args: &[&str]) -> String { String::from_utf16( - &make_command_line(OsStr::from_str(prog), + &make_command_line(OsStr::new(prog), &args.iter() .map(|a| OsString::from(a)) .collect::>())).unwrap() diff --git a/src/libstd/sys/windows/sync.rs b/src/libstd/sys/windows/sync.rs index 7614104c98..5410259540 100644 --- a/src/libstd/sys/windows/sync.rs +++ b/src/libstd/sys/windows/sync.rs @@ -8,17 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use libc::{BOOL, DWORD, LPVOID, c_ulong}; +use libc::{BOOL, DWORD, LPVOID, LONG, HANDLE, c_ulong}; use libc::types::os::arch::extra::BOOLEAN; pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PSRWLOCK = *mut SRWLOCK; pub type ULONG = c_ulong; +pub type ULONG_PTR = c_ulong; #[repr(C)] pub struct CONDITION_VARIABLE { pub ptr: LPVOID } #[repr(C)] pub struct SRWLOCK { pub ptr: LPVOID } +#[repr(C)] +pub struct CRITICAL_SECTION { + CriticalSectionDebug: LPVOID, + LockCount: LONG, + RecursionCount: LONG, + OwningThread: HANDLE, + LockSemaphore: HANDLE, + SpinCount: ULONG_PTR +} pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { ptr: 0 as *mut _, @@ -41,4 +51,10 @@ extern "system" { pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK); pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN; pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; + + pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; + pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); } diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs deleted file mode 100644 index 41e97dc847..0000000000 --- a/src/libstd/sys/windows/tcp.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2014 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. - -#![allow(deprecated)] - -use prelude::v1::*; - -use old_io::net::ip; -use old_io::IoResult; -use libc; -use libc::consts::os::extra::INVALID_SOCKET; -use mem; -use ptr; -use super::{last_error, last_net_error, sock_t}; -use sync::Arc; -use sync::atomic::{AtomicBool, Ordering}; -use sys::{self, c, set_nonblocking, wouldblock, timer}; -use sys_common::{timeout, eof, net}; - -pub use sys_common::net::TcpStream; - -pub struct Event(c::WSAEVENT); - -unsafe impl Send for Event {} -unsafe impl Sync for Event {} - -impl Event { - pub fn new() -> IoResult { - let event = unsafe { c::WSACreateEvent() }; - if event == c::WSA_INVALID_EVENT { - Err(super::last_error()) - } else { - Ok(Event(event)) - } - } - - pub fn handle(&self) -> c::WSAEVENT { let Event(handle) = *self; handle } -} - -impl Drop for Event { - fn drop(&mut self) { - unsafe { let _ = c::WSACloseEvent(self.handle()); } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP listeners -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpListener { sock: sock_t } - -unsafe impl Send for TcpListener {} -unsafe impl Sync for TcpListener {} - -impl TcpListener { - pub fn bind(addr: ip::SocketAddr) -> IoResult { - sys::init_net(); - - let sock = try!(net::socket(addr, libc::SOCK_STREAM)); - let ret = TcpListener { sock: sock }; - - let mut storage = unsafe { mem::zeroed() }; - let len = net::addr_to_sockaddr(addr, &mut storage); - let addrp = &storage as *const _ as *const libc::sockaddr; - - match unsafe { libc::bind(sock, addrp, len) } { - -1 => Err(last_net_error()), - _ => Ok(ret), - } - } - - pub fn socket(&self) -> sock_t { self.sock } - - pub fn listen(self, backlog: isize) -> IoResult { - match unsafe { libc::listen(self.socket(), backlog as libc::c_int) } { - -1 => Err(last_net_error()), - - _ => { - let accept = try!(Event::new()); - let ret = unsafe { - c::WSAEventSelect(self.socket(), accept.handle(), c::FD_ACCEPT) - }; - if ret != 0 { - return Err(last_net_error()) - } - Ok(TcpAcceptor { - inner: Arc::new(AcceptorInner { - listener: self, - abort: try!(Event::new()), - accept: accept, - closed: AtomicBool::new(false), - }), - deadline: 0, - }) - } - } - } - - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.socket(), libc::getsockname) - } -} - -impl Drop for TcpListener { - fn drop(&mut self) { - unsafe { super::close_sock(self.sock); } - } -} - -pub struct TcpAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: TcpListener, - abort: Event, - accept: Event, - closed: AtomicBool, -} - -unsafe impl Sync for AcceptorInner {} - -impl TcpAcceptor { - pub fn socket(&self) -> sock_t { self.inner.listener.socket() } - - pub fn accept(&mut self) -> IoResult { - // Unlink unix, windows cannot invoke `select` on arbitrary file - // descriptors like pipes, only sockets. Consequently, windows cannot - // use the same implementation as unix for accept() when close_accept() - // is considered. - // - // In order to implement close_accept() and timeouts, windows uses - // event handles. An acceptor-specific abort event is created which - // will only get set in close_accept(), and it will never be un-set. - // Additionally, another acceptor-specific event is associated with the - // FD_ACCEPT network event. - // - // These two events are then passed to WaitForMultipleEvents to see - // which one triggers first, and the timeout passed to this function is - // the local timeout for the acceptor. - // - // If the wait times out, then the accept timed out. If the wait - // succeeds with the abort event, then we were closed, and if the wait - // succeeds otherwise, then we do a nonblocking poll via `accept` to - // see if we can accept a connection. The connection is candidate to be - // stolen, so we do all of this in a loop as well. - let events = [self.inner.abort.handle(), self.inner.accept.handle()]; - - while !self.inner.closed.load(Ordering::SeqCst) { - let ms = if self.deadline == 0 { - c::WSA_INFINITE as u64 - } else { - let now = timer::now(); - if self.deadline < now {0} else {self.deadline - now} - }; - let ret = unsafe { - c::WSAWaitForMultipleEvents(2, events.as_ptr(), libc::FALSE, - ms as libc::DWORD, libc::FALSE) - }; - match ret { - c::WSA_WAIT_TIMEOUT => { - return Err(timeout("accept timed out")) - } - c::WSA_WAIT_FAILED => return Err(last_net_error()), - c::WSA_WAIT_EVENT_0 => break, - n => assert_eq!(n, c::WSA_WAIT_EVENT_0 + 1), - } - - let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() }; - let ret = unsafe { - c::WSAEnumNetworkEvents(self.socket(), events[1], &mut wsaevents) - }; - if ret != 0 { return Err(last_net_error()) } - - if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue } - match unsafe { - libc::accept(self.socket(), ptr::null_mut(), ptr::null_mut()) - } { - INVALID_SOCKET if wouldblock() => {} - INVALID_SOCKET => return Err(last_net_error()), - - // Accepted sockets inherit the same properties as the caller, - // so we need to deregister our event and switch the socket back - // to blocking mode - socket => { - let stream = TcpStream::new(socket); - let ret = unsafe { - c::WSAEventSelect(socket, events[1], 0) - }; - if ret != 0 { return Err(last_net_error()) } - set_nonblocking(socket, false); - return Ok(stream) - } - } - } - - Err(eof()) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, Ordering::SeqCst); - let ret = unsafe { c::WSASetEvent(self.inner.abort.handle()) }; - if ret == libc::TRUE { - Ok(()) - } else { - Err(last_net_error()) - } - } -} - -impl Clone for TcpAcceptor { - fn clone(&self) -> TcpAcceptor { - TcpAcceptor { - inner: self.inner.clone(), - deadline: 0, - } - } -} diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs deleted file mode 100644 index 8856cc26b2..0000000000 --- a/src/libstd/sys/windows/timer.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2013 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. - -//! Timers based on Windows WaitableTimers -//! -//! This implementation is meant to be used solely on windows. As with other -//! implementations, there is a worker thread which is doing all the waiting on -//! a large number of timers for all active timers in the system. This worker -//! thread uses the select() equivalent, WaitForMultipleObjects. One of the -//! objects being waited on is a signal into the worker thread to notify that -//! the incoming channel should be looked at. -//! -//! Other than that, the implementation is pretty straightforward in terms of -//! the other two implementations of timers with nothing *that* new showing up. - -#![allow(deprecated)] - -use prelude::v1::*; -use self::Req::*; - -use libc; -use ptr; - -use old_io::IoResult; -use sys_common::helper_thread::Helper; -use sync::mpsc::{channel, TryRecvError, Sender, Receiver}; - -helper_init! { static HELPER: Helper } - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - obj: libc::HANDLE, - on_worker: bool, -} - -pub enum Req { - NewTimer(libc::HANDLE, Box, bool), - RemoveTimer(libc::HANDLE, Sender<()>), -} - -unsafe impl Send for Timer {} -unsafe impl Send for Req {} - -fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { - let mut objs = vec![input]; - let mut chans = vec![]; - - 'outer: loop { - let idx = unsafe { - imp::WaitForMultipleObjects(objs.len() as libc::DWORD, - objs.as_ptr(), - 0 as libc::BOOL, - libc::INFINITE) - }; - - if idx == 0 { - loop { - match messages.try_recv() { - Ok(NewTimer(obj, c, one)) => { - objs.push(obj); - chans.push((c, one)); - } - Ok(RemoveTimer(obj, c)) => { - c.send(()).unwrap(); - match objs.iter().position(|&o| o == obj) { - Some(i) => { - drop(objs.remove(i)); - drop(chans.remove(i - 1)); - } - None => {} - } - } - // See the comment in unix::timer for why we don't have any - // asserts here and why we're likely just leaving timers on - // the floor as we exit. - Err(TryRecvError::Disconnected) => { - break 'outer; - } - Err(..) => break - } - } - } else { - let remove = { - match &mut chans[idx as usize - 1] { - &mut (ref mut c, oneshot) => { c.call(); oneshot } - } - }; - if remove { - drop(objs.remove(idx as usize)); - drop(chans.remove(idx as usize - 1)); - } - } - } -} - -// returns the current time (in milliseconds) -pub fn now() -> u64 { - let mut ticks_per_s = 0; - assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1); - let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s}; - let mut ticks = 0; - assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1); - - return (ticks as u64 * 1000) / (ticks_per_s as u64); -} - -impl Timer { - pub fn new() -> IoResult { - HELPER.boot(|| {}, helper); - - let obj = unsafe { - imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null()) - }; - if obj.is_null() { - Err(super::last_error()) - } else { - Ok(Timer { obj: obj, on_worker: false, }) - } - } - - fn remove(&mut self) { - if !self.on_worker { return } - - let (tx, rx) = channel(); - HELPER.send(RemoveTimer(self.obj, tx)); - rx.recv().unwrap(); - - self.on_worker = false; - } - - pub fn sleep(&mut self, msecs: u64) { - self.remove(); - - // there are 10^6 nanoseconds in a millisecond, and the parameter is in - // 100ns intervals, so we multiply by 10^4. - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), - ptr::null_mut(), 0) - }, 1); - - let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) }; - } - - pub fn oneshot(&mut self, msecs: u64, cb: Box) { - self.remove(); - - // see above for the calculation - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), - ptr::null_mut(), 0) - }, 1); - - HELPER.send(NewTimer(self.obj, cb, true)); - self.on_worker = true; - } - - pub fn period(&mut self, msecs: u64, cb: Box) { - self.remove(); - - // see above for the calculation - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG, - ptr::null_mut(), ptr::null_mut(), 0) - }, 1); - - HELPER.send(NewTimer(self.obj, cb, false)); - self.on_worker = true; - } -} - -impl Drop for Timer { - fn drop(&mut self) { - self.remove(); - assert!(unsafe { libc::CloseHandle(self.obj) != 0 }); - } -} - -mod imp { - use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER, - LONG, LPVOID, DWORD, c_void}; - - pub type PTIMERAPCROUTINE = *mut c_void; - - extern "system" { - pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - lpTimerName: LPCSTR) -> HANDLE; - pub fn SetWaitableTimer(hTimer: HANDLE, - pDueTime: *const LARGE_INTEGER, - lPeriod: LONG, - pfnCompletionRoutine: PTIMERAPCROUTINE, - lpArgToCompletionRoutine: LPVOID, - fResume: BOOL) -> BOOL; - pub fn WaitForMultipleObjects(nCount: DWORD, - lpHandles: *const HANDLE, - bWaitAll: BOOL, - dwMilliseconds: DWORD) -> DWORD; - pub fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) -> DWORD; - } -} diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs deleted file mode 100644 index 791c7532bd..0000000000 --- a/src/libstd/sys/windows/tty.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2014 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. - -// ignore-lexer-test FIXME #15877 - -//! Windows specific console TTY implementation -//! -//! This module contains the implementation of a Windows specific console TTY. -//! Also converts between UTF-16 and UTF-8. Windows has very poor support for -//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole -//! will panic when the codepage is set to UTF-8 and a Unicode character is -//! entered. -//! -//! FIXME -//! This implementation does not account for codepoints that are split across -//! multiple reads and writes. Also, this implementation does not expose a way -//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer -//! wrapper that performs encoding/decoding, this implementation should switch -//! to working in raw UTF-16, with such a wrapper around it. - -#![allow(deprecated)] - -use prelude::v1::*; - -use old_io::{self, IoError, IoResult, MemReader, Reader}; -use iter::repeat; -use libc::types::os::arch::extra::LPCVOID; -use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID}; -use libc::{get_osfhandle, CloseHandle}; -use mem; -use ptr; -use str::from_utf8; -use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS}; -use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT}; -use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; -use super::c::CONSOLE_SCREEN_BUFFER_INFO; -use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; -use super::c::GetConsoleScreenBufferInfo; - -fn invalid_encoding() -> IoError { - IoError { - kind: old_io::InvalidInput, - desc: "text was not valid unicode", - detail: None, - } -} - -pub fn is_tty(fd: c_int) -> bool { - let mut out: DWORD = 0; - // If this function doesn't return an error, then fd is a TTY - match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE, - &mut out as LPDWORD) } { - 0 => false, - _ => true, - } -} - -pub struct TTY { - closeme: bool, - handle: HANDLE, - utf8: MemReader, -} - -impl TTY { - pub fn new(fd: c_int) -> IoResult { - if is_tty(fd) { - // If the file descriptor is one of stdin, stderr, or stdout - // then it should not be closed by us - let closeme = match fd { - 0...2 => false, - _ => true, - }; - let handle = unsafe { get_osfhandle(fd) as HANDLE }; - Ok(TTY { - handle: handle, - utf8: MemReader::new(Vec::new()), - closeme: closeme, - }) - } else { - Err(IoError { - kind: old_io::MismatchedFileTypeForOperation, - desc: "invalid handle provided to function", - detail: None, - }) - } - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - // Read more if the buffer is empty - if self.utf8.eof() { - let mut utf16: Vec = repeat(0u16).take(0x1000).collect(); - let mut num: DWORD = 0; - match unsafe { ReadConsoleW(self.handle, - utf16.as_mut_ptr() as LPVOID, - utf16.len() as u32, - &mut num as LPDWORD, - ptr::null_mut()) } { - 0 => return Err(super::last_error()), - _ => (), - }; - utf16.truncate(num as usize); - let utf8 = match String::from_utf16(&utf16) { - Ok(utf8) => utf8.into_bytes(), - Err(..) => return Err(invalid_encoding()), - }; - self.utf8 = MemReader::new(utf8); - } - // MemReader shouldn't error here since we just filled it - Ok(self.utf8.read(buf).unwrap()) - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let utf16 = match from_utf8(buf).ok() { - Some(utf8) => { - utf8.utf16_units().collect::>() - } - None => return Err(invalid_encoding()), - }; - let mut num: DWORD = 0; - match unsafe { WriteConsoleW(self.handle, - utf16.as_ptr() as LPCVOID, - utf16.len() as u32, - &mut num as LPDWORD, - ptr::null_mut()) } { - 0 => Err(super::last_error()), - _ => Ok(()), - } - } - - pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { - // FIXME - // Somebody needs to decide on which of these flags we want - match unsafe { SetConsoleMode(self.handle, - match raw { - true => 0, - false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS | - ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE, - }) } { - 0 => Err(super::last_error()), - _ => Ok(()), - } - } - - pub fn get_winsize(&mut self) -> IoResult<(isize, isize)> { - let mut info: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() }; - match unsafe { GetConsoleScreenBufferInfo(self.handle, &mut info as *mut _) } { - 0 => Err(super::last_error()), - _ => Ok(((info.srWindow.Right + 1 - info.srWindow.Left) as isize, - (info.srWindow.Bottom + 1 - info.srWindow.Top) as isize)), - } - } -} - -impl Drop for TTY { - fn drop(&mut self) { - if self.closeme { - // Nobody cares about the return value - let _ = unsafe { CloseHandle(self.handle) }; - } - } -} diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index acd6970f11..6d8f1cba70 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -95,7 +95,7 @@ macro_rules! thread_local { (static $name:ident: $t:ty = $init:expr) => ( static $name: ::std::thread::LocalKey<$t> = { use std::cell::UnsafeCell as __UnsafeCell; - use std::thread::__local::__impl::KeyInner as __KeyInner; + use std::thread::__local::KeyInner as __KeyInner; use std::option::Option as __Option; use std::option::Option::None as __None; @@ -112,7 +112,7 @@ macro_rules! thread_local { (pub static $name:ident: $t:ty = $init:expr) => ( pub static $name: ::std::thread::LocalKey<$t> = { use std::cell::UnsafeCell as __UnsafeCell; - use std::thread::__local::__impl::KeyInner as __KeyInner; + use std::thread::__local::KeyInner as __KeyInner; use std::option::Option as __Option; use std::option::Option::None as __None; @@ -156,20 +156,20 @@ macro_rules! __thread_local_inner { #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")), thread_local)] - static $name: ::std::thread::__local::__impl::KeyInner<$t> = + static $name: ::std::thread::__local::KeyInner<$t> = __thread_local_inner!($init, $t); ); (pub static $name:ident: $t:ty = $init:expr) => ( #[cfg_attr(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")), thread_local)] - pub static $name: ::std::thread::__local::__impl::KeyInner<$t> = + pub static $name: ::std::thread::__local::KeyInner<$t> = __thread_local_inner!($init, $t); ); ($init:expr, $t:ty) => ({ #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] - const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = { - ::std::thread::__local::__impl::KeyInner { + const _INIT: ::std::thread::__local::KeyInner<$t> = { + ::std::thread::__local::KeyInner { inner: ::std::cell::UnsafeCell { value: $init }, dtor_registered: ::std::cell::UnsafeCell { value: false }, dtor_running: ::std::cell::UnsafeCell { value: false }, @@ -178,13 +178,13 @@ macro_rules! __thread_local_inner { #[allow(trivial_casts)] #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] - const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = { - ::std::thread::__local::__impl::KeyInner { + const _INIT: ::std::thread::__local::KeyInner<$t> = { + ::std::thread::__local::KeyInner { inner: ::std::cell::UnsafeCell { value: $init }, - os: ::std::thread::__local::__impl::OsStaticKey { - inner: ::std::thread::__local::__impl::OS_INIT_INNER, + os: ::std::thread::__local::OsStaticKey { + inner: ::std::thread::__local::OS_INIT_INNER, dtor: ::std::option::Option::Some( - ::std::thread::__local::__impl::destroy_value::<$t> + ::std::thread::__local::destroy_value::<$t> ), }, } @@ -226,7 +226,7 @@ pub enum LocalKeyState { } impl LocalKey { - /// Acquire a reference to the value in this TLS key. + /// Acquires a reference to the value in this TLS key. /// /// This will lazily initialize the value if this thread has not referenced /// this key yet. @@ -373,7 +373,7 @@ mod imp { arg: *mut u8, dso_handle: *mut u8) -> libc::c_int; mem::transmute::<*const (), F>(__cxa_thread_atexit_impl) - (dtor, t, __dso_handle); + (dtor, t, &__dso_handle as *const _ as *mut _); return } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 5fe6e80d6e..c65377e238 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -67,13 +67,33 @@ //! thread. This means that it can outlive its parent (the thread that spawned //! it), unless this parent is the main thread. //! +//! The parent thread can also wait on the completion of the child +//! thread; a call to `spawn` produces a `JoinHandle`, which provides +//! a `join` method for waiting: +//! +//! ```rust +//! use std::thread; +//! +//! let child = thread::spawn(move || { +//! // some work here +//! }); +//! // some work here +//! let res = child.join(); +//! ``` +//! +//! The `join` method returns a `Result` containing `Ok` of the final +//! value produced by the child thread, or `Err` of the value given to +//! a call to `panic!` if the child panicked. +//! //! ## Scoped threads //! -//! Often a parent thread uses a child thread to perform some particular task, -//! and at some point must wait for the child to complete before continuing. -//! For this scenario, use the `thread::scoped` function: +//! The `spawn` method does not allow the child and parent threads to +//! share any stack data, since that is not safe in general. However, +//! `scoped` makes it possible to share the parent's stack by forcing +//! a join before any relevant stack frames are popped: //! //! ```rust +//! # #![feature(scoped)] //! use std::thread; //! //! let guard = thread::scoped(move || { @@ -99,6 +119,7 @@ //! `println!` and `panic!` for the child thread: //! //! ```rust +//! # #![allow(unused_must_use)] //! use std::thread; //! //! thread::Builder::new().name("child1".to_string()).spawn(move || { @@ -167,14 +188,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::__local::{LocalKey, LocalKeyState}; - -#[unstable(feature = "scoped_tls", - reason = "scoped TLS has yet to have wide enough use to fully consider \ - stabilizing its interface")] -pub use self::__scoped::ScopedKey; - use prelude::v1::*; use any::Any; @@ -193,13 +206,19 @@ use time::Duration; // Thread-local storage //////////////////////////////////////////////////////////////////////////////// -#[macro_use] -#[doc(hidden)] -#[path = "local.rs"] pub mod __local; +#[macro_use] mod local; +#[macro_use] mod scoped_tls; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::local::{LocalKey, LocalKeyState}; + +#[unstable(feature = "scoped_tls", + reason = "scoped TLS has yet to have wide enough use to fully \ + consider stabilizing its interface")] +pub use self::scoped_tls::ScopedKey; -#[macro_use] -#[doc(hidden)] -#[path = "scoped.rs"] pub mod __scoped; +#[doc(hidden)] pub use self::local::__impl as __local; +#[doc(hidden)] pub use self::scoped_tls::__impl as __scoped; //////////////////////////////////////////////////////////////////////////////// // Builder @@ -216,7 +235,7 @@ pub struct Builder { } impl Builder { - /// Generate the base configuration for spawning a thread, from which + /// Generates the base configuration for spawning a thread, from which /// configuration methods can be chained. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> Builder { @@ -226,7 +245,7 @@ impl Builder { } } - /// Name the thread-to-be. Currently the name is used for identification + /// Names the thread-to-be. Currently the name is used for identification /// only in panic messages. #[stable(feature = "rust1", since = "1.0.0")] pub fn name(mut self, name: String) -> Builder { @@ -234,14 +253,14 @@ impl Builder { self } - /// Set the size of the stack for the new thread. + /// Sets the size of the stack for the new thread. #[stable(feature = "rust1", since = "1.0.0")] pub fn stack_size(mut self, size: usize) -> Builder { self.stack_size = Some(size); self } - /// Spawn a new thread, and return a join handle for it. + /// Spawns a new thread, and returns a join handle for it. /// /// The child thread may outlive the parent (unless the parent thread /// is the main thread; the whole process is terminated when the main @@ -254,14 +273,14 @@ impl Builder { /// `io::Result` to capture any failure to create the thread at /// the OS level. #[stable(feature = "rust1", since = "1.0.0")] - pub fn spawn(self, f: F) -> io::Result where - F: FnOnce(), F: Send + 'static + pub fn spawn(self, f: F) -> io::Result> where + F: FnOnce() -> T, F: Send + 'static, T: Send + 'static { self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i)) } - /// Spawn a new child thread that must be joined within a given - /// scope, and return a `JoinGuard`. + /// Spawns a new child thread that must be joined within a given + /// scope, and returns a `JoinGuard`. /// /// The join guard can be used to explicitly join the child thread (via /// `join`), returning `Result`, or it will implicitly join the child @@ -275,7 +294,8 @@ impl Builder { /// Unlike the `scoped` free function, this method yields an /// `io::Result` to capture any failure to create the thread at /// the OS level. - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -356,7 +376,7 @@ impl Builder { // Free functions //////////////////////////////////////////////////////////////////////////////// -/// Spawn a new thread, returning a `JoinHandle` for it. +/// Spawns a new thread, returning a `JoinHandle` for it. /// /// The join handle will implicitly *detach* the child thread upon being /// dropped. In this case, the child thread may outlive the parent (unless @@ -368,14 +388,16 @@ impl Builder { /// /// # Panics /// -/// Panicks if the OS fails to create a thread; use `Builder::spawn` +/// Panics if the OS fails to create a thread; use `Builder::spawn` /// to recover from such errors. #[stable(feature = "rust1", since = "1.0.0")] -pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { +pub fn spawn(f: F) -> JoinHandle where + F: FnOnce() -> T, F: Send + 'static, T: Send + 'static +{ Builder::new().spawn(f).unwrap() } -/// Spawn a new *scoped* thread, returning a `JoinGuard` for it. +/// Spawns a new *scoped* thread, returning a `JoinGuard` for it. /// /// The join guard can be used to explicitly join the child thread (via /// `join`), returning `Result`, or it will implicitly join the child @@ -386,9 +408,10 @@ pub fn spawn(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static { /// /// # Panics /// -/// Panicks if the OS fails to create a thread; use `Builder::scoped` +/// Panics if the OS fails to create a thread; use `Builder::scoped` /// to recover from such errors. -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { @@ -401,7 +424,7 @@ pub fn current() -> Thread { thread_info::current_thread() } -/// Cooperatively give up a timeslice to the OS scheduler. +/// Cooperatively gives up a timeslice to the OS scheduler. #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { unsafe { imp::yield_now() } @@ -414,7 +437,7 @@ pub fn panicking() -> bool { unwind::panicking() } -/// Invoke a closure, capturing the cause of panic if one occurs. +/// Invokes a closure, capturing the cause of panic if one occurs. /// /// This function will return `Ok(())` if the closure does not panic, and will /// return `Err(cause)` if the closure panics. The `cause` returned is the @@ -463,7 +486,7 @@ pub fn catch_panic(f: F) -> Result Ok(result.unwrap()) } -/// Put the current thread to sleep for the specified amount of time. +/// Puts the current thread to sleep for the specified amount of time. /// /// The thread may sleep longer than the duration specified due to scheduling /// specifics or platform-dependent functionality. Note that on unix platforms @@ -474,16 +497,7 @@ pub fn sleep_ms(ms: u32) { imp::sleep(Duration::milliseconds(ms as i64)) } -/// Deprecated: use `sleep_ms` instead. -#[unstable(feature = "thread_sleep", - reason = "recently added, needs an RFC, and `Duration` itself is \ - unstable")] -#[deprecated(since = "1.0.0", reason = "use sleep_ms instead")] -pub fn sleep(dur: Duration) { - imp::sleep(dur) -} - -/// Block unless or until the current thread's token is made available (may wake spuriously). +/// Blocks unless or until the current thread's token is made available (may wake spuriously). /// /// See the module doc for more detail. // @@ -502,7 +516,7 @@ pub fn park() { *guard = false; } -/// Block unless or until the current thread's token is made available or +/// Blocks unless or until the current thread's token is made available or /// the specified duration has been reached (may wake spuriously). /// /// The semantics of this function are equivalent to `park()` except that the @@ -523,13 +537,6 @@ pub fn park_timeout_ms(ms: u32) { *guard = false; } -/// Deprecated: use `park_timeout_ms` -#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] -#[deprecated(since = "1.0.0", reason = "use park_timeout_ms instead")] -pub fn park_timeout(duration: Duration) { - park_timeout_ms(duration.num_milliseconds() as u32) -} - //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -574,7 +581,7 @@ impl Thread { } } - /// Get the thread's name. + /// Gets the thread's name. #[stable(feature = "rust1", since = "1.0.0")] pub fn name(&self) -> Option<&str> { self.inner.name.as_ref().map(|s| &**s) @@ -636,27 +643,28 @@ impl JoinInner { /// handle: the ability to join a child thread is a uniquely-owned /// permission. #[stable(feature = "rust1", since = "1.0.0")] -pub struct JoinHandle(JoinInner<()>); +pub struct JoinHandle(JoinInner); -impl JoinHandle { - /// Extract a handle to the underlying thread +impl JoinHandle { + /// Extracts a handle to the underlying thread #[stable(feature = "rust1", since = "1.0.0")] pub fn thread(&self) -> &Thread { &self.0.thread } - /// Wait for the associated thread to finish. + /// Waits for the associated thread to finish. /// /// If the child thread panics, `Err` is returned with the parameter given /// to `panic`. #[stable(feature = "rust1", since = "1.0.0")] - pub fn join(mut self) -> Result<()> { + pub fn join(mut self) -> Result { self.0.join() } } #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for JoinHandle { +#[unsafe_destructor] +impl Drop for JoinHandle { fn drop(&mut self) { if !self.0.joined { unsafe { imp::detach(self.0.native) } @@ -675,7 +683,8 @@ impl Drop for JoinHandle { /// handle: the ability to join a child thread is a uniquely-owned /// permission. #[must_use = "thread will be immediately joined if `JoinGuard` is not used"] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] pub struct JoinGuard<'a, T: Send + 'a> { inner: JoinInner, _marker: PhantomData<&'a T>, @@ -685,13 +694,13 @@ pub struct JoinGuard<'a, T: Send + 'a> { unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {} impl<'a, T: Send + 'a> JoinGuard<'a, T> { - /// Extract a handle to the thread this guard will join on. + /// Extracts a handle to the thread this guard will join on. #[stable(feature = "rust1", since = "1.0.0")] pub fn thread(&self) -> &Thread { &self.inner.thread } - /// Wait for the associated thread to finish, returning the result of the + /// Waits for the associated thread to finish, returning the result of the /// thread's calculation. /// /// # Panics @@ -707,7 +716,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> { } #[unsafe_destructor] -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "scoped", + reason = "memory unsafe if destructor is avoided, see #24292")] impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> { fn drop(&mut self) { if !self.inner.joined { @@ -729,7 +739,6 @@ mod test { use any::Any; use sync::mpsc::{channel, Sender}; use result; - use std::old_io::{ChanReader, ChanWriter}; use super::{Builder}; use thread; use thunk::Thunk; @@ -968,13 +977,11 @@ mod test { #[test] fn test_park_timeout_unpark_called_other_thread() { - use std::old_io; - for _ in 0..10 { let th = thread::current(); let _guard = thread::spawn(move || { - old_io::timer::sleep(Duration::milliseconds(50)); + super::sleep_ms(50); th.unpark(); }); diff --git a/src/libstd/thread/scoped.rs b/src/libstd/thread/scoped_tls.rs similarity index 96% rename from src/libstd/thread/scoped.rs rename to src/libstd/thread/scoped_tls.rs index b384879d7a..9c0b4a5d83 100644 --- a/src/libstd/thread/scoped.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -110,7 +110,7 @@ macro_rules! __scoped_thread_local_inner { target_os = "openbsd", target_arch = "aarch64")))] const _INIT: __Key<$t> = __Key { - inner: ::std::thread::__scoped::__impl::KeyInner { + inner: ::std::thread::__scoped::KeyInner { inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, } }; @@ -121,8 +121,8 @@ macro_rules! __scoped_thread_local_inner { target_os = "openbsd", target_arch = "aarch64"))] const _INIT: __Key<$t> = __Key { - inner: ::std::thread::__scoped::__impl::KeyInner { - inner: ::std::thread::__scoped::__impl::OS_INIT, + inner: ::std::thread::__scoped::KeyInner { + inner: ::std::thread::__scoped::OS_INIT, marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>, } }; @@ -135,7 +135,7 @@ macro_rules! __scoped_thread_local_inner { reason = "scoped TLS has yet to have wide enough use to fully consider \ stabilizing its interface")] impl ScopedKey { - /// Insert a value into this scoped thread local storage slot for a + /// Inserts a value into this scoped thread local storage slot for a /// duration of a closure. /// /// While `cb` is running, the value `t` will be returned by `get` unless @@ -188,7 +188,7 @@ impl ScopedKey { cb() } - /// Get a value out of this scoped variable. + /// Gets a value out of this scoped variable. /// /// This function takes a closure which receives the value of this /// variable. diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 9b79b483b2..636a0dd697 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -12,13 +12,10 @@ #![unstable(feature = "std_misc")] +use prelude::v1::*; + use {fmt, i64}; -use ops::{Add, Sub, Mul, Div, Neg, FnOnce}; -use option::Option; -use option::Option::{Some, None}; -#[allow(deprecated)] // Int -use num::Int; -use result::Result::Ok; +use ops::{Add, Sub, Mul, Div, Neg}; /// The number of nanoseconds in a microsecond. const NANOS_PER_MICRO: i32 = 1000; diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 41b70889c9..26c1597f3a 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -43,8 +43,6 @@ //! Using traits implemented for tuples: //! //! ``` -//! use std::default::Default; -//! //! let a = (1, 2); //! let b = (3, 4); //! assert!(a != b); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 40390765dd..399810cb7f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -66,8 +66,6 @@ use parse::lexer; use ptr::P; use std::fmt; -#[allow(deprecated)] -use std::num::Int; use std::rc::Rc; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -429,14 +427,14 @@ pub struct Generics { } impl Generics { - pub fn is_parameterized(&self) -> bool { - self.lifetimes.len() + self.ty_params.len() > 0 - } pub fn is_lt_parameterized(&self) -> bool { - self.lifetimes.len() > 0 + !self.lifetimes.is_empty() } pub fn is_type_parameterized(&self) -> bool { - self.ty_params.len() > 0 + !self.ty_params.is_empty() + } + pub fn is_parameterized(&self) -> bool { + self.is_lt_parameterized() || self.is_type_parameterized() } } @@ -1142,16 +1140,24 @@ pub enum Sign { } impl Sign { - #[allow(deprecated)] // Int - pub fn new(n: T) -> Sign { - if n < Int::zero() { - Minus - } else { - Plus - } + pub fn new(n: T) -> Sign { + n.sign() } } +pub trait IntSign { + fn sign(&self) -> Sign; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl IntSign for $t { + #[allow(unused_comparisons)] + fn sign(&self) -> Sign { + if *self < 0 {Minus} else {Plus} + } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum LitIntType { SignedIntLit(IntTy, Sign), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 475970ac30..1505d1e91b 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -121,6 +121,7 @@ struct ItemFnParts<'a> { decl: &'a ast::FnDecl, unsafety: ast::Unsafety, abi: abi::Abi, + vis: ast::Visibility, generics: &'a ast::Generics, body: &'a Block, id: ast::NodeId, @@ -155,44 +156,50 @@ impl<'a> FnLikeNode<'a> { pub fn body(self) -> &'a Block { self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, body: &'a ast::Block, _| body, + |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body, |c: ClosureParts<'a>| c.body) } pub fn decl(self) -> &'a FnDecl { self.handle(|i: ItemFnParts<'a>| &*i.decl, - |_, _, sig: &'a ast::MethodSig, _, _| &sig.decl, + |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl, |c: ClosureParts<'a>| c.decl) } pub fn span(self) -> Span { self.handle(|i: ItemFnParts| i.span, - |_, _, _: &'a ast::MethodSig, _, span| span, + |_, _, _: &'a ast::MethodSig, _, _, span| span, |c: ClosureParts| c.span) } pub fn id(self) -> NodeId { self.handle(|i: ItemFnParts| i.id, - |id, _, _: &'a ast::MethodSig, _, _| id, + |id, _, _: &'a ast::MethodSig, _, _, _| id, |c: ClosureParts| c.id) } pub fn kind(self) -> visit::FnKind<'a> { let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> { - visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi) + visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.vis) }; let closure = |_: ClosureParts| { visit::FkFnBlock }; - let method = |_, ident, sig: &'a ast::MethodSig, _, _| { - visit::FkMethod(ident, sig) + let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| { + visit::FkMethod(ident, sig, vis) }; self.handle(item, method, closure) } fn handle(self, item_fn: I, method: M, closure: C) -> A where I: FnOnce(ItemFnParts<'a>) -> A, - M: FnOnce(NodeId, ast::Ident, &'a ast::MethodSig, &'a ast::Block, Span) -> A, + M: FnOnce(NodeId, + ast::Ident, + &'a ast::MethodSig, + Option, + &'a ast::Block, + Span) + -> A, C: FnOnce(ClosureParts<'a>) -> A, { match self.node { @@ -200,20 +207,20 @@ impl<'a> FnLikeNode<'a> { ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) => item_fn(ItemFnParts{ ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block, - generics: generics, abi: abi, id: i.id, span: i.span + generics: generics, abi: abi, vis: i.vis, id: i.id, span: i.span }), _ => panic!("item FnLikeNode that is not fn-like"), }, ast_map::NodeTraitItem(ti) => match ti.node { ast::MethodTraitItem(ref sig, Some(ref body)) => { - method(ti.id, ti.ident, sig, body, ti.span) + method(ti.id, ti.ident, sig, None, body, ti.span) } _ => panic!("trait method FnLikeNode that is not fn-like"), }, ast_map::NodeImplItem(ii) => { match ii.node { ast::MethodImplItem(ref sig, ref body) => { - method(ii.id, ii.ident, sig, body, ii.span) + method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) } ast::TypeImplItem(_) | ast::MacImplItem(_) => { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index c4c2249d02..0ad75c5ec8 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -440,10 +440,10 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { self.operation.visit_id(node_id); match function_kind { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_generics_helper(generics) } - visit::FkMethod(_, sig) => { + visit::FkMethod(_, sig, _) => { self.visit_generics_helper(&sig.generics) } visit::FkFnBlock => {} diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 06e447bb12..755dd3bb45 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -282,6 +282,23 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } +/// Find the value of #[export_name=*] attribute and check its validity. +pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option { + attrs.iter().fold(None, |ia,attr| { + if attr.check_name("export_name") { + if let s@Some(_) = attr.value_str() { + s + } else { + diag.span_err(attr.span, "export_name attribute has invalid format"); + diag.handler.help("use #[export_name=\"*\"]"); + None + } + } else { + ia + } + }) +} + #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, @@ -503,8 +520,8 @@ pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P]) { let name = meta.name(); if !set.insert(name.clone()) { - diagnostic.span_fatal(meta.span, - &format!("duplicate meta item `{}`", name)); + panic!(diagnostic.span_fatal(meta.span, + &format!("duplicate meta item `{}`", name))); } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index b563a5e7d6..f762822031 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -22,10 +22,11 @@ pub use self::MacroFormat::*; use std::cell::RefCell; -use std::num::ToPrimitive; use std::ops::{Add, Sub}; use std::rc::Rc; +use std::fmt; + use libc::c_uint; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -47,7 +48,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[derive(Copy, Clone, PartialEq, Hash, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Debug)] pub struct CharPos(pub usize); // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix @@ -199,6 +200,7 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { // /// A source code location used for error reporting +#[derive(Debug)] pub struct Loc { /// Information about the original source pub file: Rc, @@ -211,6 +213,7 @@ pub struct Loc { /// A source code location used as the result of lookup_char_pos_adj // Actually, *none* of the clients use the filename *or* file field; // perhaps they should just be removed. +#[derive(Debug)] pub struct LocWithOpt { pub filename: FileName, pub line: usize, @@ -219,7 +222,9 @@ pub struct LocWithOpt { } // used to be structural records. Better names, anyone? +#[derive(Debug)] pub struct FileMapAndLine { pub fm: Rc, pub line: usize } +#[derive(Debug)] pub struct FileMapAndBytePos { pub fm: Rc, pub pos: BytePos } @@ -299,9 +304,21 @@ impl ExpnId { pub type FileName = String; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct LineInfo { + /// Index of line, starting from 0. + pub line_index: usize, + + /// Column in line where span begins, starting from 0. + pub start_col: CharPos, + + /// Column in line where span ends, starting from 0, exclusive. + pub end_col: CharPos, +} + pub struct FileLines { pub file: Rc, - pub lines: Vec + pub lines: Vec } /// Identifies an offset of a multi-byte character in a FileMap @@ -342,7 +359,7 @@ impl Encodable for FileMap { // store the length try! { s.emit_u32(lines.len() as u32) }; - if lines.len() > 0 { + if !lines.is_empty() { // In order to preserve some space, we exploit the fact that // the lines list is sorted and individual lines are // probably not that long. Because of that we can store lines @@ -449,6 +466,12 @@ impl Decodable for FileMap { } } +impl fmt::Debug for FileMap { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "FileMap({})", self.name) + } +} + impl FileMap { /// EFFECT: register a start-of-line offset in the /// table of line-beginnings. @@ -467,9 +490,9 @@ impl FileMap { lines.push(pos); } - /// get a line from the list of pre-computed line-beginnings - /// - pub fn get_line(&self, line_number: usize) -> Option { + /// get a line from the list of pre-computed line-beginnings. + /// line-number here is 0-based. + pub fn get_line(&self, line_number: usize) -> Option<&str> { match self.src { Some(ref src) => { let lines = self.lines.borrow(); @@ -480,7 +503,7 @@ impl FileMap { match slice.find('\n') { Some(e) => &slice[..e], None => slice - }.to_string() + } }) } None => None @@ -545,7 +568,7 @@ impl CodeMap { // accidentally overflowing into the next filemap in case the last byte // of span is also the last byte of filemap, which leads to incorrect // results from CodeMap.span_to_*. - if src.len() > 0 && !src.ends_with("\n") { + if !src.is_empty() && !src.ends_with("\n") { src.push('\n'); } @@ -628,7 +651,7 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { - if self.files.borrow().len() == 0 && sp == DUMMY_SP { + if self.files.borrow().is_empty() && sp == DUMMY_SP { return "no-location".to_string(); } @@ -649,10 +672,29 @@ impl CodeMap { pub fn span_to_lines(&self, sp: Span) -> FileLines { let lo = self.lookup_char_pos(sp.lo); let hi = self.lookup_char_pos(sp.hi); - let mut lines = Vec::new(); - for i in lo.line - 1..hi.line { - lines.push(i); - }; + let mut lines = Vec::with_capacity(hi.line - lo.line + 1); + + // The span starts partway through the first line, + // but after that it starts from offset 0. + let mut start_col = lo.col; + + // For every line but the last, it extends from `start_col` + // and to the end of the line. Be careful because the line + // numbers in Loc are 1-based, so we subtract 1 to get 0-based + // lines. + for line_index in lo.line-1 .. hi.line-1 { + let line_len = lo.file.get_line(line_index).map(|s| s.len()).unwrap_or(0); + lines.push(LineInfo { line_index: line_index, + start_col: start_col, + end_col: CharPos::from_usize(line_len) }); + start_col = CharPos::from_usize(0); + } + + // For the last line, it extends from `start_col` to `hi.col`: + lines.push(LineInfo { line_index: hi.line - 1, + start_col: start_col, + end_col: hi.col }); + FileLines {file: lo.file, lines: lines} } @@ -765,7 +807,7 @@ impl CodeMap { loop { let lines = files[a].lines.borrow(); let lines = lines; - if lines.len() > 0 { + if !lines.is_empty() { break; } if a == 0 { @@ -821,14 +863,18 @@ impl CodeMap { pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { let mut expansions = self.expansions.borrow_mut(); expansions.push(expn_info); - ExpnId(expansions.len().to_u32().expect("too many ExpnInfo's!") - 1) + let len = expansions.len(); + if len > u32::max_value() as usize { + panic!("too many ExpnInfo's!"); + } + ExpnId(len as u32 - 1) } pub fn with_expn_info(&self, id: ExpnId, f: F) -> T where F: FnOnce(Option<&ExpnInfo>) -> T, { match id { - NO_EXPANSION => f(None), + NO_EXPANSION | COMMAND_LINE_EXPN => f(None), ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize])) } } @@ -907,6 +953,7 @@ pub struct MalformedCodemapPositions { #[cfg(test)] mod test { use super::*; + use std::rc::Rc; #[test] fn t1 () { @@ -914,10 +961,10 @@ mod test { let fm = cm.new_filemap("blork.rs".to_string(), "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); - assert_eq!(fm.get_line(0), Some("first line.".to_string())); + assert_eq!(fm.get_line(0), Some("first line.")); // TESTING BROKEN BEHAVIOR: fm.next_line(BytePos(10)); - assert_eq!(fm.get_line(1), Some(".".to_string())); + assert_eq!(fm.get_line(1), Some(".")); } #[test] @@ -1045,7 +1092,54 @@ mod test { assert_eq!(file_lines.file.name, "blork.rs"); assert_eq!(file_lines.lines.len(), 1); - assert_eq!(file_lines.lines[0], 1); + assert_eq!(file_lines.lines[0].line_index, 1); + } + + /// Given a string like " ^~~~~~~~~~~~ ", produces a span + /// coverting that range. The idea is that the string has the same + /// length as the input, and we uncover the byte positions. Note + /// that this can span lines and so on. + fn span_from_selection(input: &str, selection: &str) -> Span { + assert_eq!(input.len(), selection.len()); + let left_index = selection.find('^').unwrap() as u32; + let right_index = selection.rfind('~').unwrap() as u32; + Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } + } + + fn new_filemap_and_lines(cm: &CodeMap, filename: &str, input: &str) -> Rc { + let fm = cm.new_filemap(filename.to_string(), input.to_string()); + let mut byte_pos: u32 = 0; + for line in input.lines() { + // register the start of this line + fm.next_line(BytePos(byte_pos)); + + // update byte_pos to include this line and the \n at the end + byte_pos += line.len() as u32 + 1; + } + fm + } + + /// Test span_to_snippet and span_to_lines for a span coverting 3 + /// lines in the middle of a file. + #[test] + fn span_to_snippet_and_lines_spanning_multiple_lines() { + let cm = CodeMap::new(); + let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n"; + let selection = " \n ^~\n~~~\n~~~~~ \n \n"; + new_filemap_and_lines(&cm, "blork.rs", inputtext); + let span = span_from_selection(inputtext, selection); + + // check that we are extracting the text we thought we were extracting + assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD"); + + // check that span_to_lines gives us the complete result with the lines/cols we expected + let lines = cm.span_to_lines(span); + let expected = vec![ + LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) }, + LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) }, + LineInfo { line_index: 3, start_col: CharPos(0), end_col: CharPos(5) } + ]; + assert_eq!(lines.lines, expected); } #[test] diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index f35cc8c8d2..f3715d765e 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -18,6 +18,7 @@ use codemap; use diagnostics; use std::cell::{RefCell, Cell}; +use std::cmp; use std::fmt; use std::io::prelude::*; use std::io; @@ -28,28 +29,39 @@ use libc; /// maximum number of lines we will print for each error; arbitrary. const MAX_LINES: usize = 6; -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of /// the source code covered by the span. FullSpan(Span), + /// Similar to a FullSpan, but the cited position is the end of + /// the span, instead of the start. Used, at least, for telling + /// compiletest/runtest to look at the last line of the span + /// (since `end_highlight_lines` displays an arrow to the end + /// of the span). + EndSpan(Span), + + /// A suggestion renders with both with an initial line for the + /// message, prefixed by file:linenum, followed by a summary + /// of hypothetical source code, where the `String` is spliced + /// into the lines in place of the code covered by the span. + Suggestion(Span, String), + /// A FileLine renders with just a line for the message prefixed /// by file:linenum. FileLine(Span), } impl RenderSpan { - fn span(self) -> Span { - match self { - FullSpan(s) | FileLine(s) => s - } - } - fn is_full_span(&self) -> bool { - match self { - &FullSpan(..) => true, - &FileLine(..) => false, + fn span(&self) -> Span { + match *self { + FullSpan(s) | + Suggestion(s, _) | + EndSpan(s) | + FileLine(s) => + s } } } @@ -68,10 +80,11 @@ pub trait Emitter { sp: RenderSpan, msg: &str, lvl: Level); } -/// This structure is used to signify that a task has panicked with a fatal error -/// from the diagnostics. You can use this with the `Any` trait to figure out -/// how a rustc task died (if so desired). +/// Used as a return value to signify a fatal error occurred. (It is also +/// used as the argument to panic at the moment, but that will eventually +/// not be true.) #[derive(Copy, Clone)] +#[must_use] pub struct FatalError; /// Signifies that the compiler died with an explicit call to `.bug` @@ -88,13 +101,13 @@ pub struct SpanHandler { } impl SpanHandler { - pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { + pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { self.handler.emit(Some((&self.cm, sp)), msg, Fatal); - panic!(FatalError); + return FatalError; } - pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> ! { + pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { self.handler.emit_with_code(Some((&self.cm, sp)), msg, code, Fatal); - panic!(FatalError); + return FatalError; } pub fn span_err(&self, sp: Span, msg: &str) { self.handler.emit(Some((&self.cm, sp)), msg, Error); @@ -114,11 +127,17 @@ impl SpanHandler { self.handler.emit(Some((&self.cm, sp)), msg, Note); } pub fn span_end_note(&self, sp: Span, msg: &str) { - self.handler.custom_emit(&self.cm, FullSpan(sp), msg, Note); + self.handler.custom_emit(&self.cm, EndSpan(sp), msg, Note); } pub fn span_help(&self, sp: Span, msg: &str) { self.handler.emit(Some((&self.cm, sp)), msg, Help); } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.handler.custom_emit(&self.cm, Suggestion(sp, suggestion), msg, Help); + } pub fn fileline_note(&self, sp: Span, msg: &str) { self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note); } @@ -406,8 +425,8 @@ impl Emitter for EmitterWriter { let error = match cmsp { Some((cm, COMMAND_LINE_SP)) => emit(self, cm, FileLine(COMMAND_LINE_SP), - msg, code, lvl, false), - Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl, false), + msg, code, lvl), + Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl), None => print_diagnostic(self, "", lvl, msg, code), }; @@ -419,7 +438,7 @@ impl Emitter for EmitterWriter { fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { - match emit(self, cm, sp, msg, None, lvl, true) { + match emit(self, cm, sp, msg, None, lvl) { Ok(()) => {} Err(e) => panic!("failed to print diagnostics: {:?}", e), } @@ -427,35 +446,40 @@ impl Emitter for EmitterWriter { } fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, code: Option<&str>, lvl: Level, custom: bool) -> io::Result<()> { + msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { let sp = rsp.span(); // We cannot check equality directly with COMMAND_LINE_SP // since PartialEq is manually implemented to ignore the ExpnId let ss = if sp.expn_id == COMMAND_LINE_EXPN { "".to_string() + } else if let EndSpan(_) = rsp { + let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; + cm.span_to_string(span_end) } else { cm.span_to_string(sp) }; - if custom { - // we want to tell compiletest/runtest to look at the last line of the - // span (since `custom_highlight_lines` displays an arrow to the end of - // the span) - let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; - let ses = cm.span_to_string(span_end); - try!(print_diagnostic(dst, &ses[..], lvl, msg, code)); - if rsp.is_full_span() { - try!(custom_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); - } - } else { - try!(print_diagnostic(dst, &ss[..], lvl, msg, code)); - if rsp.is_full_span() { + + try!(print_diagnostic(dst, &ss[..], lvl, msg, code)); + + match rsp { + FullSpan(_) => { try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); + try!(print_macro_backtrace(dst, cm, sp)); + } + EndSpan(_) => { + try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); + try!(print_macro_backtrace(dst, cm, sp)); + } + Suggestion(_, ref suggestion) => { + try!(highlight_suggestion(dst, cm, sp, suggestion)); + try!(print_macro_backtrace(dst, cm, sp)); + } + FileLine(..) => { + // no source text in this case! } } - if sp != COMMAND_LINE_SP { - try!(print_macro_backtrace(dst, cm, sp)); - } + match code { Some(code) => match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { @@ -471,29 +495,90 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, Ok(()) } +fn highlight_suggestion(err: &mut EmitterWriter, + cm: &codemap::CodeMap, + sp: Span, + suggestion: &str) + -> io::Result<()> +{ + let lines = cm.span_to_lines(sp); + assert!(!lines.lines.is_empty()); + + // To build up the result, we want to take the snippet from the first + // line that precedes the span, prepend that with the suggestion, and + // then append the snippet from the last line that trails the span. + let fm = &lines.file; + + let first_line = &lines.lines[0]; + let prefix = fm.get_line(first_line.line_index) + .map(|l| &l[..first_line.start_col.0]) + .unwrap_or(""); + + let last_line = lines.lines.last().unwrap(); + let suffix = fm.get_line(last_line.line_index) + .map(|l| &l[last_line.end_col.0..]) + .unwrap_or(""); + + let complete = format!("{}{}{}", prefix, suggestion, suffix); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let fm = &*lines.file; + let mut lines = complete.lines(); + for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { + let elided_line_num = format!("{}", line_index+1); + try!(write!(&mut err.dst, "{0}:{1:2$} {3}\n", + fm.name, "", elided_line_num.len(), line)); + } + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); + try!(write!(&mut err.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), elided_line_num.len())); + } + + Ok(()) +} + fn highlight_lines(err: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, - lines: codemap::FileLines) -> io::Result<()> { + lines: codemap::FileLines) + -> io::Result<()> +{ let fm = &*lines.file; - let mut elided = false; - let mut display_lines = &lines.lines[..]; - if display_lines.len() > MAX_LINES { - display_lines = &display_lines[0..MAX_LINES]; - elided = true; - } + let line_strings: Option> = + lines.lines.iter() + .map(|info| fm.get_line(info.line_index)) + .collect(); + + let line_strings = match line_strings { + None => { return Ok(()); } + Some(line_strings) => line_strings + }; + + // Display only the first MAX_LINES lines. + let all_lines = lines.lines.len(); + let display_lines = cmp::min(all_lines, MAX_LINES); + let display_line_infos = &lines.lines[..display_lines]; + let display_line_strings = &line_strings[..display_lines]; + // Print the offending lines - for &line_number in display_lines { - if let Some(line) = fm.get_line(line_number) { - try!(write!(&mut err.dst, "{}:{} {}\n", fm.name, - line_number + 1, line)); - } + for (line_info, line) in display_line_infos.iter().zip(display_line_strings.iter()) { + try!(write!(&mut err.dst, "{}:{} {}\n", + fm.name, + line_info.line_index + 1, + line)); } - if elided { - let last_line = display_lines[display_lines.len() - 1]; - let s = format!("{}:{} ", fm.name, last_line + 1); + + // If we elided something, put an ellipsis. + if display_lines < all_lines { + let last_line_index = display_line_infos.last().unwrap().line_index; + let s = format!("{}:{} ", fm.name, last_line_index + 1); try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len())); } @@ -502,7 +587,7 @@ fn highlight_lines(err: &mut EmitterWriter, if lines.lines.len() == 1 { let lo = cm.lookup_char_pos(sp.lo); let mut digits = 0; - let mut num = (lines.lines[0] + 1) / 10; + let mut num = (lines.lines[0].line_index + 1) / 10; // how many digits must be indent past? while num > 0 { num /= 10; digits += 1; } @@ -514,7 +599,7 @@ fn highlight_lines(err: &mut EmitterWriter, for _ in 0..skip { s.push(' '); } - if let Some(orig) = fm.get_line(lines.lines[0]) { + if let Some(orig) = fm.get_line(lines.lines[0].line_index) { let mut col = skip; let mut lastc = ' '; let mut iter = orig.chars().enumerate(); @@ -574,12 +659,12 @@ fn highlight_lines(err: &mut EmitterWriter, } /// Here are the differences between this and the normal `highlight_lines`: -/// `custom_highlight_lines` will always put arrow on the last byte of the +/// `end_highlight_lines` will always put arrow on the last byte of the /// span (instead of the first byte). Also, when the span is too long (more -/// than 6 lines), `custom_highlight_lines` will print the first line, then +/// than 6 lines), `end_highlight_lines` will print the first line, then /// dot dot dot, then last line, whereas `highlight_lines` prints the first /// six lines. -fn custom_highlight_lines(w: &mut EmitterWriter, +fn end_highlight_lines(w: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, @@ -589,32 +674,32 @@ fn custom_highlight_lines(w: &mut EmitterWriter, let lines = &lines.lines[..]; if lines.len() > MAX_LINES { - if let Some(line) = fm.get_line(lines[0]) { + if let Some(line) = fm.get_line(lines[0].line_index) { try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - lines[0] + 1, line)); + lines[0].line_index + 1, line)); } try!(write!(&mut w.dst, "...\n")); - let last_line_number = lines[lines.len() - 1]; - if let Some(last_line) = fm.get_line(last_line_number) { + let last_line_index = lines[lines.len() - 1].line_index; + if let Some(last_line) = fm.get_line(last_line_index) { try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - last_line_number + 1, last_line)); + last_line_index + 1, last_line)); } } else { - for &line_number in lines { - if let Some(line) = fm.get_line(line_number) { + for line_info in lines { + if let Some(line) = fm.get_line(line_info.line_index) { try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - line_number + 1, line)); + line_info.line_index + 1, line)); } } } - let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1); + let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); let hi = cm.lookup_char_pos(sp.hi); let skip = last_line_start.width(false); let mut s = String::new(); for _ in 0..skip { s.push(' '); } - if let Some(orig) = fm.get_line(lines[0]) { + if let Some(orig) = fm.get_line(lines[0].line_index) { let iter = orig.chars().enumerate(); for (pos, ch) in iter { // Span seems to use half-opened interval, so subtract 1 diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index d256698b88..6915969032 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -90,17 +90,17 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) p.token != token::Colon && p.token != token::ModSep { - if outputs.len() != 0 { - p.eat(&token::Comma); + if !outputs.is_empty() { + panictry!(p.eat(&token::Comma)); } - let (constraint, _str_style) = p.parse_str(); + let (constraint, _str_style) = panictry!(p.parse_str()); let span = p.last_span; - p.expect(&token::OpenDelim(token::Paren)); + panictry!(p.expect(&token::OpenDelim(token::Paren))); let out = p.parse_expr(); - p.expect(&token::CloseDelim(token::Paren)); + panictry!(p.expect(&token::CloseDelim(token::Paren))); // Expands a read+write operand into two operands. // @@ -130,11 +130,11 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) p.token != token::Colon && p.token != token::ModSep { - if inputs.len() != 0 { - p.eat(&token::Comma); + if !inputs.is_empty() { + panictry!(p.eat(&token::Comma)); } - let (constraint, _str_style) = p.parse_str(); + let (constraint, _str_style) = panictry!(p.parse_str()); if constraint.starts_with("=") { cx.span_err(p.last_span, "input operand constraint contains '='"); @@ -142,9 +142,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) cx.span_err(p.last_span, "input operand constraint contains '+'"); } - p.expect(&token::OpenDelim(token::Paren)); + panictry!(p.expect(&token::OpenDelim(token::Paren))); let input = p.parse_expr(); - p.expect(&token::CloseDelim(token::Paren)); + panictry!(p.expect(&token::CloseDelim(token::Paren))); inputs.push((constraint, input)); } @@ -154,11 +154,11 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) p.token != token::Colon && p.token != token::ModSep { - if clobs.len() != 0 { - p.eat(&token::Comma); + if !clobs.is_empty() { + panictry!(p.eat(&token::Comma)); } - let (s, _str_style) = p.parse_str(); + let (s, _str_style) = panictry!(p.parse_str()); if OPTIONS.iter().any(|&opt| s == opt) { cx.span_warn(p.last_span, "expected a clobber, found an option"); @@ -167,7 +167,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } } Options => { - let (option, _str_style) = p.parse_str(); + let (option, _str_style) = panictry!(p.parse_str()); if option == "volatile" { // Indicates that the inline assembly has side effects @@ -182,7 +182,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } if p.token == token::Comma { - p.eat(&token::Comma); + panictry!(p.eat(&token::Comma)); } } StateNone => () @@ -194,12 +194,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) match (&p.token, state.next(), state.next().next()) { (&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => { - p.bump(); + panictry!(p.bump()); break 'statement; } (&token::Colon, st, _) | (&token::ModSep, _, st) => { - p.bump(); + panictry!(p.bump()); state = st; } (&token::Eof, _, _) => break 'statement, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 71fba789ff..9e36c75dda 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -208,10 +208,11 @@ impl IdentMacroExpander for F } // Use a macro because forwarding to a simple function has type system issues -macro_rules! make_stmt_default { +macro_rules! make_stmts_default { ($me:expr) => { $me.make_expr().map(|e| { - P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))) + SmallVector::one(P(codemap::respan( + e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID)))) }) } } @@ -238,12 +239,12 @@ pub trait MacResult { None } - /// Create a statement. + /// Create zero or more statements. /// /// By default this attempts to create an expression statement, /// returning None if that fails. - fn make_stmt(self: Box) -> Option> { - make_stmt_default!(self) + fn make_stmts(self: Box) -> Option>> { + make_stmts_default!(self) } } @@ -276,7 +277,7 @@ make_MacEager! { pat: P, items: SmallVector>, impl_items: SmallVector>, - stmt: P, + stmts: SmallVector>, } impl MacResult for MacEager { @@ -292,10 +293,10 @@ impl MacResult for MacEager { self.impl_items } - fn make_stmt(self: Box) -> Option> { - match self.stmt { - None => make_stmt_default!(self), - s => s, + fn make_stmts(self: Box) -> Option>> { + match self.stmts.as_ref().map_or(0, |s| s.len()) { + 0 => make_stmts_default!(self), + _ => self.stmts, } } @@ -384,10 +385,11 @@ impl MacResult for DummyResult { Some(SmallVector::zero()) } } - fn make_stmt(self: Box) -> Option> { - Some(P(codemap::respan(self.span, - ast::StmtExpr(DummyResult::raw_expr(self.span), - ast::DUMMY_NODE_ID)))) + fn make_stmts(self: Box) -> Option>> { + Some(SmallVector::one(P( + codemap::respan(self.span, + ast::StmtExpr(DummyResult::raw_expr(self.span), + ast::DUMMY_NODE_ID))))) } } @@ -603,7 +605,6 @@ impl<'a> ExtCtxt<'a> { None => self.bug("missing top span") }) } - pub fn print_backtrace(&self) { } pub fn backtrace(&self) -> ExpnId { self.backtrace } pub fn original_span(&self) -> Span { let mut expn_id = self.backtrace; @@ -652,9 +653,9 @@ impl<'a> ExtCtxt<'a> { pub fn bt_push(&mut self, ei: ExpnInfo) { self.recursion_count += 1; if self.recursion_count > self.ecfg.recursion_limit { - self.span_fatal(ei.call_site, + panic!(self.span_fatal(ei.call_site, &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name)); + ei.callee.name))); } let mut call_site = ei.call_site; @@ -698,8 +699,7 @@ impl<'a> ExtCtxt<'a> { /// substitute; we never hit resolve/type-checking so the dummy /// value doesn't have to match anything) pub fn span_fatal(&self, sp: Span, msg: &str) -> ! { - self.print_backtrace(); - self.parse_sess.span_diagnostic.span_fatal(sp, msg); + panic!(self.parse_sess.span_diagnostic.span_fatal(sp, msg)); } /// Emit `msg` attached to `sp`, without immediately stopping @@ -708,35 +708,27 @@ impl<'a> ExtCtxt<'a> { /// Compilation will be stopped in the near future (at the end of /// the macro expansion phase). pub fn span_err(&self, sp: Span, msg: &str) { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_err(sp, msg); } pub fn span_warn(&self, sp: Span, msg: &str) { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_warn(sp, msg); } pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_unimpl(sp, msg); } pub fn span_bug(&self, sp: Span, msg: &str) -> ! { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_bug(sp, msg); } pub fn span_note(&self, sp: Span, msg: &str) { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_note(sp, msg); } pub fn span_help(&self, sp: Span, msg: &str) { - self.print_backtrace(); self.parse_sess.span_diagnostic.span_help(sp, msg); } pub fn fileline_help(&self, sp: Span, msg: &str) { - self.print_backtrace(); self.parse_sess.span_diagnostic.fileline_help(sp, msg); } pub fn bug(&self, msg: &str) -> ! { - self.print_backtrace(); self.parse_sess.span_diagnostic.handler().bug(msg); } pub fn trace_macros(&self) -> bool { @@ -782,7 +774,7 @@ pub fn check_zero_tts(cx: &ExtCtxt, sp: Span, tts: &[ast::TokenTree], name: &str) { - if tts.len() != 0 { + if !tts.is_empty() { cx.span_err(sp, &format!("{} takes no arguments", name)); } } @@ -817,7 +809,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt, let mut es = Vec::new(); while p.token != token::Eof { es.push(cx.expander().fold_expr(p.parse_expr())); - if p.eat(&token::Comma) { + if panictry!(p.eat(&token::Comma)){ continue; } if p.token != token::Eof { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d0853761e..cde16d2541 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -767,7 +767,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let loc = self.codemap().lookup_char_pos(span.lo); let expr_file = self.expr_str(span, token::intern_and_get_ident(&loc.file.name)); - let expr_line = self.expr_usize(span, loc.line); + let expr_line = self.expr_u32(span, loc.line as u32); let expr_file_line_tuple = self.expr_tuple(span, vec!(expr_file, expr_line)); let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple); self.expr_call_global( diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 6a2209bf0a..8af7fb7b26 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -29,7 +29,7 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, let mut p = cx.new_parser_from_tts(tts); let cfg = p.parse_meta_item(); - if !p.eat(&token::Eof) { + if !panictry!(p.eat(&token::Eof)){ cx.span_err(sp, "expected 1 cfg-pattern"); return DummyResult::expr(sp); } diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index f89f3ab55f..95eb68ca0d 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -89,7 +89,7 @@ fn cs_clone( } } - if all_fields.len() >= 1 && all_fields[0].name.is_none() { + if !all_fields.is_empty() && all_fields[0].name.is_none() { // enum-like let subcalls = all_fields.iter().map(subcall).collect(); let path = cx.expr_path(ctor_path); diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 06255f4677..6425e6a28e 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -240,7 +240,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span, let encoder = cx.expr_ident(trait_span, blkarg); let emit_variant_arg = cx.ident_of("emit_enum_variant_arg"); let mut stmts = Vec::new(); - if fields.len() > 0 { + if !fields.is_empty() { let last = fields.len() - 1; for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() { let enc = cx.expr_method_call(span, self_.clone(), diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 397775fdbf..7f6f29df53 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -201,6 +201,7 @@ use ext::base::ExtCtxt; use ext::build::AstBuilder; use codemap::{self, DUMMY_SP}; use codemap::Span; +use diagnostic::SpanHandler; use fold::MoveMap; use owned_slice::OwnedSlice; use parse::token::InternedString; @@ -391,6 +392,7 @@ impl<'a> TraitDef<'a> { ast::ItemEnum(ref enum_def, ref generics) => { self.expand_enum_def(cx, enum_def, + &item.attrs[..], item.ident, generics) } @@ -653,6 +655,7 @@ impl<'a> TraitDef<'a> { fn expand_enum_def(&self, cx: &mut ExtCtxt, enum_def: &EnumDef, + type_attrs: &[ast::Attribute], type_ident: Ident, generics: &Generics) -> P { let mut field_tys = Vec::new(); @@ -687,6 +690,7 @@ impl<'a> TraitDef<'a> { method_def.expand_enum_method_body(cx, self, enum_def, + type_attrs, type_ident, self_args, &nonself_args[..]) @@ -706,13 +710,30 @@ impl<'a> TraitDef<'a> { } } -fn variant_to_pat(cx: &mut ExtCtxt, sp: Span, enum_ident: ast::Ident, variant: &ast::Variant) - -> P { - let path = cx.path(sp, vec![enum_ident, variant.node.name]); - cx.pat(sp, match variant.node.kind { - ast::TupleVariantKind(..) => ast::PatEnum(path, None), - ast::StructVariantKind(..) => ast::PatStruct(path, Vec::new(), true), - }) +fn find_repr_type_name(diagnostic: &SpanHandler, + type_attrs: &[ast::Attribute]) -> &'static str { + let mut repr_type_name = "i32"; + for a in type_attrs { + for r in &attr::find_repr_attrs(diagnostic, a) { + repr_type_name = match *r { + attr::ReprAny | attr::ReprPacked => continue, + attr::ReprExtern => "i32", + + attr::ReprInt(_, attr::SignedInt(ast::TyIs)) => "isize", + attr::ReprInt(_, attr::SignedInt(ast::TyI8)) => "i8", + attr::ReprInt(_, attr::SignedInt(ast::TyI16)) => "i16", + attr::ReprInt(_, attr::SignedInt(ast::TyI32)) => "i32", + attr::ReprInt(_, attr::SignedInt(ast::TyI64)) => "i64", + + attr::ReprInt(_, attr::UnsignedInt(ast::TyUs)) => "usize", + attr::ReprInt(_, attr::UnsignedInt(ast::TyU8)) => "u8", + attr::ReprInt(_, attr::UnsignedInt(ast::TyU16)) => "u16", + attr::ReprInt(_, attr::UnsignedInt(ast::TyU32)) => "u32", + attr::ReprInt(_, attr::UnsignedInt(ast::TyU64)) => "u64", + } + } + } + repr_type_name } impl<'a> MethodDef<'a> { @@ -891,7 +912,7 @@ impl<'a> MethodDef<'a> { } // transpose raw_fields - let fields = if raw_fields.len() > 0 { + let fields = if !raw_fields.is_empty() { let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter()); let first_field = raw_fields.next().unwrap(); let mut other_fields: Vec, P)>> @@ -983,12 +1004,13 @@ impl<'a> MethodDef<'a> { cx: &mut ExtCtxt, trait_: &TraitDef, enum_def: &EnumDef, + type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec>, nonself_args: &[P]) -> P { self.build_enum_match_tuple( - cx, trait_, enum_def, type_ident, self_args, nonself_args) + cx, trait_, enum_def, type_attrs, type_ident, self_args, nonself_args) } @@ -1022,6 +1044,7 @@ impl<'a> MethodDef<'a> { cx: &mut ExtCtxt, trait_: &TraitDef, enum_def: &EnumDef, + type_attrs: &[ast::Attribute], type_ident: Ident, self_args: Vec>, nonself_args: &[P]) -> P { @@ -1044,8 +1067,8 @@ impl<'a> MethodDef<'a> { .collect::>(); // The `vi_idents` will be bound, solely in the catch-all, to - // a series of let statements mapping each self_arg to a usize - // corresponding to its variant index. + // a series of let statements mapping each self_arg to an int + // value corresponding to its discriminant. let vi_idents: Vec = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); cx.ident_of(&vi_suffix[..]) }) @@ -1160,33 +1183,44 @@ impl<'a> MethodDef<'a> { // unreachable-pattern error. // if variants.len() > 1 && self_args.len() > 1 { - let arms: Vec = variants.iter().enumerate() - .map(|(index, variant)| { - let pat = variant_to_pat(cx, sp, type_ident, &**variant); - let lit = ast::LitInt(index as u64, ast::UnsignedIntLit(ast::TyUs)); - cx.arm(sp, vec![pat], cx.expr_lit(sp, lit)) - }).collect(); - // Build a series of let statements mapping each self_arg - // to a usize corresponding to its variant index. + // to its discriminant value. If this is a C-style enum + // with a specific repr type, then casts the values to + // that type. Otherwise casts to `i32` (the default repr + // type). + // // i.e. for `enum E { A, B(1), C(T, T) }`, and a deriving // with three Self args, builds three statements: // // ``` - // let __self0_vi = match self { - // A => 0, B(..) => 1, C(..) => 2 - // }; - // let __self1_vi = match __arg1 { - // A => 0, B(..) => 1, C(..) => 2 - // }; - // let __self2_vi = match __arg2 { - // A => 0, B(..) => 1, C(..) => 2 - // }; + // let __self0_vi = unsafe { + // std::intrinsics::discriminant_value(&self) } as i32; + // let __self1_vi = unsafe { + // std::intrinsics::discriminant_value(&__arg1) } as i32; + // let __self2_vi = unsafe { + // std::intrinsics::discriminant_value(&__arg2) } as i32; // ``` let mut index_let_stmts: Vec> = Vec::new(); + + let target_type_name = + find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); + for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) { - let variant_idx = cx.expr_match(sp, self_arg.clone(), arms.clone()); - let let_stmt = cx.stmt_let(sp, false, ident, variant_idx); + let path = vec![cx.ident_of_std("core"), + cx.ident_of("intrinsics"), + cx.ident_of("discriminant_value")]; + let call = cx.expr_call_global( + sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]); + let variant_value = cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: sp })); + + let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name)); + let variant_disr = cx.expr_cast(sp, variant_value, target_ty); + let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); index_let_stmts.push(let_stmt); } @@ -1214,7 +1248,7 @@ impl<'a> MethodDef<'a> { match_arms.push(catch_all_match_arm); - } else if variants.len() == 0 { + } else if variants.is_empty() { // As an additional wrinkle, For a zero-variant enum A, // currently the compiler // will accept `fn (a: &Self) { match *a { } }` diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index d8c50b5a09..65554efdd6 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -61,7 +61,6 @@ pub mod clone; pub mod encodable; pub mod decodable; pub mod hash; -pub mod rand; pub mod show; pub mod default; pub mod primitive; @@ -168,8 +167,6 @@ derive_traits! { "PartialOrd" => ord::expand_deriving_ord, "Ord" => totalord::expand_deriving_totalord, - "Rand" => rand::expand_deriving_rand, - "Debug" => show::expand_deriving_show, "Default" => default::expand_deriving_default, diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs deleted file mode 100644 index 631e5f979d..0000000000 --- a/src/libsyntax/ext/deriving/rand.rs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2012-2013 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 ast; -use ast::{MetaItem, Item, Expr}; -use codemap::Span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::deriving::generic::*; -use ext::deriving::generic::ty::*; -use ptr::P; - -pub fn expand_deriving_rand(cx: &mut ExtCtxt, - span: Span, - mitem: &MetaItem, - item: &Item, - push: F) where - F: FnOnce(P), -{ - cx.span_warn(span, - "`#[derive(Rand)]` is deprecated in favour of `#[derive_Rand]` from \ - `rand_macros` on crates.io"); - - if !cx.use_std { - // FIXME(#21880): lift this requirement. - cx.span_err(span, "this trait cannot be derived with #![no_std]"); - return; - } - - let trait_def = TraitDef { - span: span, - attributes: Vec::new(), - path: path!(std::rand::Rand), - additional_bounds: Vec::new(), - generics: LifetimeBounds::empty(), - methods: vec!( - MethodDef { - name: "rand", - generics: LifetimeBounds { - lifetimes: Vec::new(), - bounds: vec!(("R", - vec!( path!(std::rand::Rng) ))), - }, - explicit_self: None, - args: vec!( - Ptr(box Literal(Path::new_local("R")), - Borrowed(None, ast::MutMutable)) - ), - ret_ty: Self_, - attributes: Vec::new(), - combine_substructure: combine_substructure(Box::new(|a, b, c| { - rand_substructure(a, b, c) - })) - } - ), - associated_types: Vec::new(), - }; - trait_def.expand(cx, mitem, item, push) -} - -fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let rng = match substr.nonself_args { - [ref rng] => rng, - _ => cx.bug("Incorrect number of arguments to `rand` in `derive(Rand)`") - }; - let rand_ident = vec!( - cx.ident_of("std"), - cx.ident_of("rand"), - cx.ident_of("Rand"), - cx.ident_of("rand") - ); - let rand_call = |cx: &mut ExtCtxt, span| { - cx.expr_call_global(span, - rand_ident.clone(), - vec!(rng.clone())) - }; - - return match *substr.fields { - StaticStruct(_, ref summary) => { - let path = cx.path_ident(trait_span, substr.type_ident); - rand_thing(cx, trait_span, path, summary, rand_call) - } - StaticEnum(_, ref variants) => { - if variants.is_empty() { - cx.span_err(trait_span, "`Rand` cannot be derived for enums with no variants"); - // let compilation continue - return cx.expr_usize(trait_span, 0); - } - - let variant_count = cx.expr_usize(trait_span, variants.len()); - - let rand_name = cx.path_all(trait_span, - true, - rand_ident.clone(), - Vec::new(), - Vec::new(), - Vec::new()); - let rand_name = cx.expr_path(rand_name); - - // ::rand::Rand::rand(rng) - let rv_call = cx.expr_call(trait_span, - rand_name, - vec!(rng.clone())); - - // need to specify the usize-ness of the random number - let usize_ty = cx.ty_ident(trait_span, cx.ident_of("usize")); - let value_ident = cx.ident_of("__value"); - let let_statement = cx.stmt_let_typed(trait_span, - false, - value_ident, - usize_ty, - rv_call); - - // rand() % variants.len() - let value_ref = cx.expr_ident(trait_span, value_ident); - let rand_variant = cx.expr_binary(trait_span, - ast::BiRem, - value_ref, - variant_count); - - let mut arms = variants.iter().enumerate().map(|(i, &(ident, v_span, ref summary))| { - let i_expr = cx.expr_usize(v_span, i); - let pat = cx.pat_lit(v_span, i_expr); - - let path = cx.path(v_span, vec![substr.type_ident, ident]); - let thing = rand_thing(cx, v_span, path, summary, |cx, sp| rand_call(cx, sp)); - cx.arm(v_span, vec!( pat ), thing) - }).collect:: >(); - - // _ => {} at the end. Should never occur - arms.push(cx.arm_unreachable(trait_span)); - - let match_expr = cx.expr_match(trait_span, rand_variant, arms); - - let block = cx.block(trait_span, vec!( let_statement ), Some(match_expr)); - cx.expr_block(block) - } - _ => cx.bug("Non-static method in `derive(Rand)`") - }; - - fn rand_thing(cx: &mut ExtCtxt, - trait_span: Span, - ctor_path: ast::Path, - summary: &StaticFields, - mut rand_call: F) - -> P where - F: FnMut(&mut ExtCtxt, Span) -> P, - { - let path = cx.expr_path(ctor_path.clone()); - match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { - path - } else { - let exprs = fields.iter().map(|span| rand_call(cx, *span)).collect(); - cx.expr_call(trait_span, path, exprs) - } - } - Named(ref fields) => { - let rand_fields = fields.iter().map(|&(ident, span)| { - let e = rand_call(cx, span); - cx.field_imm(span, ident, e) - }).collect(); - cx.expr_struct(trait_span, ctor_path, rand_fields) - } - } - } -} diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index f72303985e..2ca74644b3 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -65,7 +65,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { let mut exprs = match get_exprs_from_tts(cx, sp, tts) { - Some(ref exprs) if exprs.len() == 0 => { + Some(ref exprs) if exprs.is_empty() => { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::expr(sp); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ee2cf9017b..74ec219af1 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -14,7 +14,6 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac}; use ast::{StmtExpr, StmtSemi}; use ast::TokenTree; use ast; -use ast_util::path_to_ident; use ext::mtwt; use ext::build::AstBuilder; use attr; @@ -34,30 +33,6 @@ use visit; use visit::Visitor; use std_inject; -pub fn expand_type(t: P, - fld: &mut MacroExpander, - impl_ty: Option>) - -> P { - debug!("expanding type {:?} with impl_ty {:?}", t, impl_ty); - let t = match (t.node.clone(), impl_ty) { - // Expand uses of `Self` in impls to the concrete type. - (ast::Ty_::TyPath(None, ref path), Some(ref impl_ty)) => { - let path_as_ident = path_to_ident(path); - // Note unhygenic comparison here. I think this is correct, since - // even though `Self` is almost just a type parameter, the treatment - // for this expansion is as if it were a keyword. - if path_as_ident.is_some() && - path_as_ident.unwrap().name == token::special_idents::type_self.name { - impl_ty.clone() - } else { - t - } - } - _ => t - }; - fold::noop_fold_ty(t, fld) -} - pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { e.and_then(|ast::Expr {id, node, span}| match node { // expr_mac should really be expr_ext or something; it's the @@ -80,7 +55,7 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { fully_expanded.map(|e| ast::Expr { id: ast::DUMMY_NODE_ID, node: e.node, - span: span, + span: fld.new_span(span), }) } @@ -745,37 +720,49 @@ pub fn expand_item_mac(it: P, } /// Expand a stmt -fn expand_stmt(s: Stmt, fld: &mut MacroExpander) -> SmallVector> { - let (mac, style) = match s.node { +fn expand_stmt(stmt: P, fld: &mut MacroExpander) -> SmallVector> { + let stmt = stmt.and_then(|stmt| stmt); + let (mac, style) = match stmt.node { StmtMac(mac, style) => (mac, style), - _ => return expand_non_macro_stmt(s, fld) + _ => return expand_non_macro_stmt(stmt, fld) }; - let expanded_stmt = match expand_mac_invoc(mac.and_then(|m| m), s.span, - |r| r.make_stmt(), - mark_stmt, fld) { - Some(stmt) => stmt, - None => { - return SmallVector::zero(); + + let maybe_new_items = + expand_mac_invoc(mac.and_then(|m| m), stmt.span, + |r| r.make_stmts(), + |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)), + fld); + + let mut fully_expanded = match maybe_new_items { + Some(stmts) => { + // Keep going, outside-in. + let new_items = stmts.into_iter().flat_map(|s| { + fld.fold_stmt(s).into_iter() + }).collect(); + fld.cx.bt_pop(); + new_items } + None => SmallVector::zero() }; - // Keep going, outside-in. - let fully_expanded = fld.fold_stmt(expanded_stmt); - fld.cx.bt_pop(); - + // If this is a macro invocation with a semicolon, then apply that + // semicolon to the final statement produced by expansion. if style == MacStmtWithSemicolon { - fully_expanded.into_iter().map(|s| s.map(|Spanned {node, span}| { - Spanned { - node: match node { - StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id), - _ => node /* might already have a semi */ - }, - span: span - } - })).collect() - } else { - fully_expanded + if let Some(stmt) = fully_expanded.pop() { + let new_stmt = stmt.map(|Spanned {node, span}| { + Spanned { + node: match node { + StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id), + _ => node /* might already have a semi */ + }, + span: span + } + }); + fully_expanded.push(new_stmt); + } } + + fully_expanded } // expand a non-macro stmt. this is essentially the fallthrough for @@ -854,7 +841,7 @@ fn expand_non_macro_stmt(Spanned {node, span: stmt_span}: Stmt, fld: &mut MacroE fn expand_arm(arm: ast::Arm, fld: &mut MacroExpander) -> ast::Arm { // expand pats... they might contain macro uses: let expanded_pats = arm.pats.move_map(|pat| fld.fold_pat(pat)); - if expanded_pats.len() == 0 { + if expanded_pats.is_empty() { panic!("encountered match arm with 0 patterns"); } // all of the pats must have the same set of bindings, so use the @@ -1354,13 +1341,11 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P, /// A tree-folder that performs macro expansion pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - // The type of the impl currently being expanded. - current_impl_type: Option>, } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> { - MacroExpander { cx: cx, current_impl_type: None } + MacroExpander { cx: cx } } } @@ -1374,14 +1359,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_item(&mut self, item: P) -> SmallVector> { - let prev_type = self.current_impl_type.clone(); - if let ast::Item_::ItemImpl(_, _, _, _, ref ty, _) = item.node { - self.current_impl_type = Some(ty.clone()); - } - - let result = expand_item(item, self); - self.current_impl_type = prev_type; - result + expand_item(item, self) } fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ { @@ -1389,7 +1367,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { } fn fold_stmt(&mut self, stmt: P) -> SmallVector> { - stmt.and_then(|stmt| expand_stmt(stmt, self)) + expand_stmt(stmt, self) } fn fold_block(&mut self, block: P) -> P { @@ -1410,11 +1388,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> { .into_iter().map(|i| i.expect_impl_item()).collect() } - fn fold_ty(&mut self, t: P) -> P { - let impl_type = self.current_impl_type.clone(); - expand_type(t, self, impl_type) - } - fn new_span(&mut self, span: Span) -> Span { new_span(self.cx, span) } @@ -1541,8 +1514,8 @@ fn mark_pat(pat: P, m: Mrk) -> P { } // apply a given mark to the given stmt. Used following the expansion of a macro. -fn mark_stmt(expr: P, m: Mrk) -> P { - Marker{mark:m}.fold_stmt(expr) +fn mark_stmt(stmt: P, m: Mrk) -> P { + Marker{mark:m}.fold_stmt(stmt) .expect_one("marking a stmt didn't return exactly one stmt") } @@ -1684,7 +1657,7 @@ mod test { fn expand_crate_str(crate_str: String) -> ast::Crate { let ps = parse::new_parse_sess(); - let crate_ast = string_to_parser(&ps, crate_str).parse_crate_mod(); + let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast) } @@ -1770,7 +1743,8 @@ mod test { // suggests that this can only occur in the presence of local-expand, which // we have no plans to support. ... unless it's needed for item hygiene.... #[ignore] - #[test] fn issue_8062(){ + #[test] + fn issue_8062(){ run_renaming_test( &("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); getx!();}", vec!(vec!(0)), true), 0) @@ -1781,7 +1755,8 @@ mod test { // (just g) along the other, so the result of the whole thing should // be "let z_123 = 3; z_123" #[ignore] - #[test] fn issue_6994(){ + #[test] + fn issue_6994(){ run_renaming_test( &("macro_rules! g (($x:ident) => ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)})); @@ -1792,7 +1767,8 @@ mod test { // match variable hygiene. Should expand into // fn z() {match 8 {x_1 => {match 9 {x_2 | x_2 if x_2 == x_1 => x_2 + x_1}}}} - #[test] fn issue_9384(){ + #[test] + fn issue_9384(){ run_renaming_test( &("macro_rules! bad_macro (($ex:expr) => ({match 9 {x | x if x == $ex => x + $ex}})); fn z() {match 8 {x => bad_macro!(x)}}", @@ -1805,7 +1781,8 @@ mod test { // interpolated nodes weren't getting labeled. // should expand into // fn main(){let g1_1 = 13; g1_1}} - #[test] fn pat_expand_issue_15221(){ + #[test] + fn pat_expand_issue_15221(){ run_renaming_test( &("macro_rules! inner ( ($e:pat ) => ($e)); macro_rules! outer ( ($e:pat ) => (inner!($e))); @@ -1821,7 +1798,8 @@ mod test { // method arg hygiene // method expands to fn get_x(&self_0, x_1: i32) {self_0 + self_2 + x_3 + x_1} - #[test] fn method_arg_hygiene(){ + #[test] + fn method_arg_hygiene(){ run_renaming_test( &("macro_rules! inject_x (()=>(x)); macro_rules! inject_self (()=>(self)); @@ -1834,7 +1812,8 @@ mod test { // ooh, got another bite? // expands to struct A; impl A {fn thingy(&self_1) {self_1;}} - #[test] fn method_arg_hygiene_2(){ + #[test] + fn method_arg_hygiene_2(){ run_renaming_test( &("struct A; macro_rules! add_method (($T:ty) => @@ -1847,7 +1826,8 @@ mod test { // item fn hygiene // expands to fn q(x_1: i32){fn g(x_2: i32){x_2 + x_1};} - #[test] fn issue_9383(){ + #[test] + fn issue_9383(){ run_renaming_test( &("macro_rules! bad_macro (($ex:expr) => (fn g(x: i32){ x + $ex })); fn q(x: i32) { bad_macro!(x); }", @@ -1857,7 +1837,8 @@ mod test { // closure arg hygiene (ExprClosure) // expands to fn f(){(|x_1 : i32| {(x_2 + x_1)})(3);} - #[test] fn closure_arg_hygiene(){ + #[test] + fn closure_arg_hygiene(){ run_renaming_test( &("macro_rules! inject_x (()=>(x)); fn f(){(|x : i32| {(inject_x!() + x)})(3);}", @@ -1867,7 +1848,8 @@ mod test { } // macro_rules in method position. Sadly, unimplemented. - #[test] fn macro_in_method_posn(){ + #[test] + fn macro_in_method_posn(){ expand_crate_str( "macro_rules! my_method (() => (fn thirteen(&self) -> i32 {13})); struct A; @@ -1877,7 +1859,8 @@ mod test { // another nested macro // expands to impl Entries {fn size_hint(&self_1) {self_1;} - #[test] fn item_macro_workaround(){ + #[test] + fn item_macro_workaround(){ run_renaming_test( &("macro_rules! item { ($i:item) => {$i}} struct Entries; @@ -1904,7 +1887,7 @@ mod test { let binding_name = mtwt::resolve(bindings[binding_idx]); let binding_marks = mtwt::marksof(bindings[binding_idx].ctxt, invalid_name); // shouldmatch can't name varrefs that don't exist: - assert!((shouldmatch.len() == 0) || + assert!((shouldmatch.is_empty()) || (varrefs.len() > *shouldmatch.iter().max().unwrap())); for (idx,varref) in varrefs.iter().enumerate() { let print_hygiene_debug_info = || { @@ -1961,7 +1944,8 @@ mod test { } } - #[test] fn fmt_in_macro_used_inside_module_macro() { + #[test] + fn fmt_in_macro_used_inside_module_macro() { let crate_str = "macro_rules! fmt_wrap(($b:expr)=>($b.to_string())); macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}})); foo_module!(); diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 2fe77bf7a5..4fe5ab1554 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -17,6 +17,7 @@ use ext::base::*; use ext::base; use ext::build::AstBuilder; use fmt_macros as parse; +use fold::Folder; use parse::token::special_idents; use parse::token; use ptr::P; @@ -37,6 +38,10 @@ enum Position { struct Context<'a, 'b:'a> { ecx: &'a mut ExtCtxt<'b>, + /// The macro's call site. References to unstable formatting internals must + /// use this span to pass the stability checker. + macsp: Span, + /// The span of the format string literal. fmtsp: Span, /// Parsed argument expressions and the types that we've found so far for @@ -92,7 +97,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let fmtstr = p.parse_expr(); let mut named = false; while p.token != token::Eof { - if !p.eat(&token::Comma) { + if !panictry!(p.eat(&token::Comma)) { ecx.span_err(sp, "expected token: `,`"); return None; } @@ -101,7 +106,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) named = true; let ident = match p.token { token::Ident(i, _) => { - p.bump(); + panictry!(p.bump()); i } _ if named => { @@ -120,7 +125,7 @@ fn parse_args(ecx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let interned_name = token::get_ident(ident); let name = &interned_name[..]; - p.expect(&token::Eq); + panictry!(p.expect(&token::Eq)); let e = p.parse_expr(); match names.get(name) { None => {} @@ -307,7 +312,7 @@ impl<'a, 'b> Context<'a, 'b> { } fn trans_count(&self, c: parse::Count) -> P { - let sp = self.fmtsp; + let sp = self.macsp; let count = |c, arg| { let mut path = Context::rtpath(self.ecx, "Count"); path.push(self.ecx.ident_of(c)); @@ -345,7 +350,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Translate a `parse::Piece` to a static `rt::Argument` or append /// to the `literal` string. fn trans_piece(&mut self, piece: &parse::Piece) -> Option> { - let sp = self.fmtsp; + let sp = self.macsp; match *piece { parse::String(s) => { self.literal.push_str(s); @@ -441,22 +446,22 @@ impl<'a, 'b> Context<'a, 'b> { piece_ty: P, pieces: Vec>) -> P { - let fmtsp = piece_ty.span; - let ty = ecx.ty_rptr(fmtsp, - ecx.ty(fmtsp, ast::TyVec(piece_ty)), - Some(ecx.lifetime(fmtsp, special_idents::static_lifetime.name)), + let sp = piece_ty.span; + let ty = ecx.ty_rptr(sp, + ecx.ty(sp, ast::TyVec(piece_ty)), + Some(ecx.lifetime(sp, special_idents::static_lifetime.name)), ast::MutImmutable); - let slice = ecx.expr_vec_slice(fmtsp, pieces); + let slice = ecx.expr_vec_slice(sp, pieces); let st = ast::ItemStatic(ty, ast::MutImmutable, slice); let name = ecx.ident_of(name); - let item = ecx.item(fmtsp, name, vec![], st); - let decl = respan(fmtsp, ast::DeclItem(item)); + let item = ecx.item(sp, name, vec![], st); + let decl = respan(sp, ast::DeclItem(item)); // Wrap the declaration in a block so that it forms a single expression. - ecx.expr_block(ecx.block(fmtsp, - vec![P(respan(fmtsp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], - Some(ecx.expr_ident(fmtsp, name)))) + ecx.expr_block(ecx.block(sp, + vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], + Some(ecx.expr_ident(sp, name)))) } /// Actually builds the expression which the iformat! block will be expanded @@ -496,7 +501,7 @@ impl<'a, 'b> Context<'a, 'b> { let name = self.ecx.ident_of(&format!("__arg{}", i)); pats.push(self.ecx.pat_ident(e.span, name)); - locals.push(Context::format_arg(self.ecx, e.span, arg_ty, + locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, name))); heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -514,7 +519,7 @@ impl<'a, 'b> Context<'a, 'b> { *name)); pats.push(self.ecx.pat_ident(e.span, lname)); names[*self.name_positions.get(name).unwrap()] = - Some(Context::format_arg(self.ecx, e.span, arg_ty, + Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, lname))); heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -565,7 +570,7 @@ impl<'a, 'b> Context<'a, 'b> { // Build up the static array which will store our precompiled // nonstandard placeholders, if there are any. let piece_ty = self.ecx.ty_path(self.ecx.path_global( - self.fmtsp, + self.macsp, Context::rtpath(self.ecx, "Argument"))); let fmt = Context::static_array(self.ecx, "__STATIC_FMTARGS", @@ -575,14 +580,14 @@ impl<'a, 'b> Context<'a, 'b> { ("new_v1_formatted", vec![pieces, args_slice, fmt]) }; - self.ecx.expr_call_global(self.fmtsp, vec!( + self.ecx.expr_call_global(self.macsp, vec!( self.ecx.ident_of_std("core"), self.ecx.ident_of("fmt"), self.ecx.ident_of("Arguments"), self.ecx.ident_of(fn_name)), fn_args) } - fn format_arg(ecx: &ExtCtxt, sp: Span, + fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span, ty: &ArgumentType, arg: P) -> P { let trait_ = match *ty { @@ -606,7 +611,7 @@ impl<'a, 'b> Context<'a, 'b> { } } Unsigned => { - return ecx.expr_call_global(sp, vec![ + return ecx.expr_call_global(macsp, vec![ ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), @@ -619,7 +624,7 @@ impl<'a, 'b> Context<'a, 'b> { ecx.ident_of("fmt"), ecx.ident_of(trait_), ecx.ident_of("fmt")]); - ecx.expr_call_global(sp, vec![ + ecx.expr_call_global(macsp, vec![ ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), @@ -649,6 +654,11 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, names: HashMap>) -> P { let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect(); + let macsp = ecx.call_site(); + // Expand the format literal so that efmt.span will have a backtrace. This + // is essential for locating a bug when the format literal is generated in + // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). + let efmt = ecx.expander().fold_expr(efmt); let mut cx = Context { ecx: ecx, args: args, @@ -663,9 +673,9 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, pieces: Vec::new(), str_pieces: Vec::new(), all_pieces_simple: true, - fmtsp: sp, + macsp: macsp, + fmtsp: efmt.span, }; - cx.fmtsp = efmt.span; let fmt = match expr_to_string(cx.ecx, efmt, "format argument must be a string literal.") { @@ -678,7 +688,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, loop { match parser.next() { Some(piece) => { - if parser.errors.len() > 0 { break } + if !parser.errors.is_empty() { break } cx.verify_piece(&piece); match cx.trans_piece(&piece) { Some(piece) => { diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index 8173dd93f7..9869108952 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -26,8 +26,6 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt, return base::DummyResult::any(sp); } - cx.print_backtrace(); - println!("{}", print::pprust::tts_to_string(tts)); // any so that `log_syntax` can be invoked as an expression and item. diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index f514f72d56..ce83b84efe 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -266,7 +266,7 @@ pub fn outer_mark(ctxt: SyntaxContext) -> Mrk { /// Push a name... unless it matches the one on top, in which /// case pop and discard (so two of the same marks cancel) fn xor_push(marks: &mut Vec, mark: Mrk) { - if (marks.len() > 0) && (*marks.last().unwrap() == mark) { + if (!marks.is_empty()) && (*marks.last().unwrap() == mark) { marks.pop().unwrap(); } else { marks.push(mark); diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 87299721fb..5776fa9974 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -781,11 +781,11 @@ fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[ast::TokenTree]) p.quote_depth += 1; let cx_expr = p.parse_expr(); - if !p.eat(&token::Comma) { - p.fatal("expected token `,`"); + if !panictry!(p.eat(&token::Comma)) { + panic!(p.fatal("expected token `,`")); } - let tts = p.parse_all_token_trees(); + let tts = panictry!(p.parse_all_token_trees()); p.abort_if_errors(); (cx_expr, tts) diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 31d8b207bb..d91659bafe 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -117,11 +117,11 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree while self.p.token != token::Eof { match self.p.parse_item() { Some(item) => ret.push(item), - None => self.p.span_fatal( + None => panic!(self.p.span_fatal( self.p.span, &format!("expected item, found `{}`", self.p.this_token_to_string()) - ) + )) } } Some(ret) @@ -184,6 +184,11 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) return DummyResult::expr(sp); } Ok(..) => { + // Add this input file to the code map to make it available as + // dependency information, but don't enter it's contents + let filename = format!("{}", file.display()); + cx.codemap().new_filemap(filename, "".to_string()); + base::MacEager::expr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b7d40a46f3..9c3a556b21 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -226,10 +226,10 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc]) } Occupied(..) => { let string = token::get_ident(bind_name); - p_s.span_diagnostic + panic!(p_s.span_diagnostic .span_fatal(sp, &format!("duplicated bind name: {}", - &string)) + &string))) } } } @@ -260,10 +260,10 @@ pub fn parse_or_else(sess: &ParseSess, match parse(sess, cfg, rdr, &ms[..]) { Success(m) => m, Failure(sp, str) => { - sess.span_diagnostic.span_fatal(sp, &str[..]) + panic!(sess.span_diagnostic.span_fatal(sp, &str[..])) } Error(sp, str) => { - sess.span_diagnostic.span_fatal(sp, &str[..]) + panic!(sess.span_diagnostic.span_fatal(sp, &str[..])) } } } @@ -457,7 +457,7 @@ pub fn parse(sess: &ParseSess, return Failure(sp, "unexpected end of macro invocation".to_string()); } } else { - if (bb_eis.len() > 0 && next_eis.len() > 0) + if (!bb_eis.is_empty() && !next_eis.is_empty()) || bb_eis.len() > 1 { let nts = bb_eis.iter().map(|ei| { match ei.top_elts.get_tt(ei.idx) { @@ -472,12 +472,12 @@ pub fn parse(sess: &ParseSess, "local ambiguity: multiple parsing options: \ built-in NTs {} or {} other options.", nts, next_eis.len()).to_string()); - } else if bb_eis.len() == 0 && next_eis.len() == 0 { + } else if bb_eis.is_empty() && next_eis.is_empty() { return Failure(sp, format!("no rules expected the token `{}`", pprust::token_to_string(&tok)).to_string()); - } else if next_eis.len() > 0 { + } else if !next_eis.is_empty() { /* Now process the next token */ - while next_eis.len() > 0 { + while !next_eis.is_empty() { cur_eis.push(next_eis.pop().unwrap()); } rdr.next_token(); @@ -504,7 +504,7 @@ pub fn parse(sess: &ParseSess, } } - assert!(cur_eis.len() > 0); + assert!(!cur_eis.is_empty()); } } @@ -512,46 +512,46 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { p.quote_depth += 1; //but in theory, non-quoted tts might be useful - let res = token::NtTT(P(p.parse_token_tree())); + let res = token::NtTT(P(panictry!(p.parse_token_tree()))); p.quote_depth -= 1; return res; } _ => {} } // check at the beginning and the parser checks after each bump - p.check_unknown_macro_variable(); + panictry!(p.check_unknown_macro_variable()); match name { "item" => match p.parse_item() { Some(i) => token::NtItem(i), - None => p.fatal("expected an item keyword") + None => panic!(p.fatal("expected an item keyword")) }, - "block" => token::NtBlock(p.parse_block()), + "block" => token::NtBlock(panictry!(p.parse_block())), "stmt" => match p.parse_stmt() { Some(s) => token::NtStmt(s), - None => p.fatal("expected a statement") + None => panic!(p.fatal("expected a statement")) }, "pat" => token::NtPat(p.parse_pat()), "expr" => token::NtExpr(p.parse_expr()), "ty" => token::NtTy(p.parse_ty()), // this could be handled like a token, since it is one "ident" => match p.token { - token::Ident(sn,b) => { p.bump(); token::NtIdent(box sn,b) } + token::Ident(sn,b) => { panictry!(p.bump()); token::NtIdent(box sn,b) } _ => { let token_str = pprust::token_to_string(&p.token); - p.fatal(&format!("expected ident, found {}", - &token_str[..])) + panic!(p.fatal(&format!("expected ident, found {}", + &token_str[..]))) } }, "path" => { - token::NtPath(box p.parse_path(LifetimeAndTypesWithoutColons)) + token::NtPath(box panictry!(p.parse_path(LifetimeAndTypesWithoutColons))) } "meta" => token::NtMeta(p.parse_meta_item()), _ => { - p.span_fatal_help(sp, + panic!(p.span_fatal_help(sp, &format!("invalid fragment specifier `{}`", name), "valid fragment specifiers are `ident`, `block`, \ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \ - and `item`") + and `item`")) } } } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 1e53db6030..730da6cc59 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -29,6 +29,11 @@ use std::rc::Rc; struct ParserAnyMacro<'a> { parser: RefCell>, + + /// Span of the expansion site of the macro this parser is for + site_span: Span, + /// The ident of the macro we're parsing + macro_ident: ast::Ident } impl<'a> ParserAnyMacro<'a> { @@ -41,7 +46,7 @@ impl<'a> ParserAnyMacro<'a> { fn ensure_complete_parse(&self, allow_semi: bool) { let mut parser = self.parser.borrow_mut(); if allow_semi && parser.token == token::Semi { - parser.bump() + panictry!(parser.bump()) } if parser.token != token::Eof { let token_str = parser.this_token_to_string(); @@ -50,6 +55,12 @@ impl<'a> ParserAnyMacro<'a> { token_str); let span = parser.span; parser.span_err(span, &msg[..]); + + let name = token::get_ident(self.macro_ident); + let msg = format!("caused by the macro expansion here; the usage \ + of `{}` is likely invalid in this context", + name); + parser.span_note(self.site_span, &msg[..]); } } } @@ -81,17 +92,31 @@ impl<'a> MacResult for ParserAnyMacro<'a> { let mut parser = self.parser.borrow_mut(); match parser.token { token::Eof => break, - _ => ret.push(parser.parse_impl_item()) + _ => ret.push(panictry!(parser.parse_impl_item())) } } self.ensure_complete_parse(false); Some(ret) } - fn make_stmt(self: Box>) -> Option> { - let ret = self.parser.borrow_mut().parse_stmt(); - self.ensure_complete_parse(true); - ret + fn make_stmts(self: Box>) + -> Option>> { + let mut ret = SmallVector::zero(); + loop { + let mut parser = self.parser.borrow_mut(); + match parser.token { + token::Eof => break, + _ => match parser.parse_stmt_nopanic() { + Ok(maybe_stmt) => match maybe_stmt { + Some(stmt) => ret.push(stmt), + None => (), + }, + Err(_) => break, + } + } + } + self.ensure_complete_parse(false); + Some(ret) } } @@ -142,7 +167,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, MatchedNonterminal(NtTT(ref lhs_tt)) => { let lhs_tt = match **lhs_tt { TtDelimited(_, ref delim) => &delim.tts[..], - _ => cx.span_fatal(sp, "malformed macro lhs") + _ => panic!(cx.span_fatal(sp, "malformed macro lhs")) }; match TokenTree::parse(cx, lhs_tt, arg) { @@ -153,7 +178,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, match **tt { // ignore delimiters TtDelimited(_, ref delimed) => delimed.tts.clone(), - _ => cx.span_fatal(sp, "macro rhs must be delimited"), + _ => panic!(cx.span_fatal(sp, "macro rhs must be delimited")), } }, _ => cx.span_bug(sp, "bad thing in rhs") @@ -164,24 +189,30 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, imported_from, rhs); let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr)); - p.check_unknown_macro_variable(); + panictry!(p.check_unknown_macro_variable()); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return box ParserAnyMacro { parser: RefCell::new(p), + + // Pass along the original expansion site and the name of the macro + // so we can print a useful error message if the parse of the expanded + // macro leaves unparsed tokens. + site_span: sp, + macro_ident: name } } Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; best_fail_msg = (*msg).clone(); }, - Error(sp, ref msg) => cx.span_fatal(sp, &msg[..]) + Error(sp, ref msg) => panic!(cx.span_fatal(sp, &msg[..])) } } _ => cx.bug("non-matcher found in parsed lhses") } } - cx.span_fatal(best_fail_spot, &best_fail_msg[..]); + panic!(cx.span_fatal(best_fail_spot, &best_fail_msg[..])); } // Note that macro-by-example's input is also matched against a token tree: diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 0d92bd761b..e39b46a2d3 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -247,22 +247,22 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { match lockstep_iter_size(&TtSequence(sp, seq.clone()), r) { LisUnconstrained => { - r.sp_diag.span_fatal( + panic!(r.sp_diag.span_fatal( sp.clone(), /* blame macro writer */ "attempted to repeat an expression \ containing no syntax \ - variables matched as repeating at this depth"); + variables matched as repeating at this depth")); } LisContradiction(ref msg) => { // FIXME #2887 blame macro invoker instead - r.sp_diag.span_fatal(sp.clone(), &msg[..]); + panic!(r.sp_diag.span_fatal(sp.clone(), &msg[..])); } LisConstraint(len, _) => { if len == 0 { if seq.op == ast::OneOrMore { // FIXME #2887 blame invoker - r.sp_diag.span_fatal(sp.clone(), - "this must repeat at least once"); + panic!(r.sp_diag.span_fatal(sp.clone(), + "this must repeat at least once")); } r.stack.last_mut().unwrap().idx += 1; @@ -306,10 +306,10 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { return ret_val; } MatchedSeq(..) => { - r.sp_diag.span_fatal( + panic!(r.sp_diag.span_fatal( r.cur_span, /* blame the macro writer */ &format!("variable '{:?}' is still repeating at this depth", - token::get_ident(ident))); + token::get_ident(ident)))); } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dbddd9dd44..659eb34323 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -399,7 +399,7 @@ impl<'a> Context<'a> { } else { self.gate_feature("custom_attribute", attr.span, &format!("The attribute `{}` is currently \ - unknown to the the compiler and \ + unknown to the compiler and \ may have meaning \ added to it in the future", name)); @@ -409,6 +409,9 @@ impl<'a> Context<'a> { pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: &str) { diag.span_err(span, explain); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } diag.fileline_help(span, &format!("add #![feature({})] to the \ crate attributes to enable", feature)); @@ -416,6 +419,9 @@ pub fn emit_feature_err(diag: &SpanHandler, feature: &str, span: Span, explain: pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) { diag.span_warn(span, explain); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; } if diag.handler.can_emit_warnings { diag.fileline_help(span, &format!("add #![feature({})] to the \ crate attributes to silence this warning", @@ -638,13 +644,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { span: Span, _node_id: NodeId) { match fn_kind { - visit::FkItemFn(_, _, _, abi) if abi == Abi::RustIntrinsic => { + visit::FkItemFn(_, _, _, abi, _) if abi == Abi::RustIntrinsic => { self.gate_feature("intrinsics", span, "intrinsics are subject to change") } - visit::FkItemFn(_, _, _, abi) | - visit::FkMethod(_, &ast::MethodSig { abi, .. }) if abi == Abi::RustCall => { + visit::FkItemFn(_, _, _, abi, _) | + visit::FkMethod(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => { self.gate_feature("unboxed_closures", span, "rust-call ABI is subject to change") diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d4451cc7b7..d7033ce7e4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1176,7 +1176,7 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> } ExprMethodCall(i, tps, args) => { ExprMethodCall( - respan(i.span, folder.fold_ident(i.node)), + respan(folder.new_span(i.span), folder.fold_ident(i.node)), tps.move_map(|x| folder.fold_ty(x)), args.move_map(|x| folder.fold_expr(x))) } @@ -1246,11 +1246,13 @@ pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> } ExprField(el, ident) => { ExprField(folder.fold_expr(el), - respan(ident.span, folder.fold_ident(ident.node))) + respan(folder.new_span(ident.span), + folder.fold_ident(ident.node))) } ExprTupField(el, ident) => { ExprTupField(folder.fold_expr(el), - respan(ident.span, folder.fold_usize(ident.node))) + respan(folder.new_span(ident.span), + folder.fold_usize(ident.node))) } ExprIndex(el, er) => { ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 0980acd343..3f36d0e8ed 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -30,7 +30,6 @@ #![feature(collections)] #![feature(core)] #![feature(libc)] -#![feature(old_path)] #![feature(quote, unsafe_destructor)] #![feature(rustc_private)] #![feature(staged_api)] @@ -50,6 +49,21 @@ extern crate libc; extern crate serialize as rustc_serialize; // used by deriving +// A variant of 'try!' that panics on Err(FatalError). This is used as a +// crutch on the way towards a non-panic!-prone parser. It should be used +// for fatal parsing errors; eventually we plan to convert all code using +// panictry to just use normal try +macro_rules! panictry { + ($e:expr) => ({ + use std::result::Result::{Ok, Err}; + use diagnostic::FatalError; + match $e { + Ok(e) => e, + Err(FatalError) => panic!(FatalError) + } + }) +} + pub mod util { pub mod interner; #[cfg(test)] diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index a5dd4f2222..18588c5935 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -45,10 +45,10 @@ impl<'a> ParserAttr for Parser<'a> { self.span.hi ); if attr.node.style != ast::AttrOuter { - self.fatal("expected outer comment"); + panic!(self.fatal("expected outer comment")); } attrs.push(attr); - self.bump(); + panictry!(self.bump()); } _ => break } @@ -66,11 +66,11 @@ impl<'a> ParserAttr for Parser<'a> { let (span, value, mut style) = match self.token { token::Pound => { let lo = self.span.lo; - self.bump(); + panictry!(self.bump()); if permit_inner { self.expected_tokens.push(TokenType::Token(token::Not)); } let style = if self.token == token::Not { - self.bump(); + panictry!(self.bump()); if !permit_inner { let span = self.span; self.span_err(span, @@ -84,21 +84,21 @@ impl<'a> ParserAttr for Parser<'a> { ast::AttrOuter }; - self.expect(&token::OpenDelim(token::Bracket)); + panictry!(self.expect(&token::OpenDelim(token::Bracket))); let meta_item = self.parse_meta_item(); let hi = self.span.hi; - self.expect(&token::CloseDelim(token::Bracket)); + panictry!(self.expect(&token::CloseDelim(token::Bracket))); (mk_sp(lo, hi), meta_item, style) } _ => { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `#`, found `{}`", token_str)); + panic!(self.fatal(&format!("expected `#`, found `{}`", token_str))); } }; if permit_inner && self.token == token::Semi { - self.bump(); + panictry!(self.bump()); self.span_warn(span, "this inner attribute syntax is deprecated. \ The new syntax is `#![foo]`, with a bang and no semicolon"); style = ast::AttrInner; @@ -142,7 +142,7 @@ impl<'a> ParserAttr for Parser<'a> { lo, hi); if attr.node.style == ast::AttrInner { attrs.push(attr); - self.bump(); + panictry!(self.bump()); } else { break; } @@ -166,19 +166,19 @@ impl<'a> ParserAttr for Parser<'a> { match nt_meta { Some(meta) => { - self.bump(); + panictry!(self.bump()); return meta; } None => {} } let lo = self.span.lo; - let ident = self.parse_ident(); + let ident = panictry!(self.parse_ident()); let name = self.id_to_interned_str(ident); match self.token { token::Eq => { - self.bump(); - let lit = self.parse_lit(); + panictry!(self.bump()); + let lit = panictry!(self.parse_lit()); // FIXME #623 Non-string meta items are not serialized correctly; // just forbid them for now match lit.node { @@ -206,10 +206,10 @@ impl<'a> ParserAttr for Parser<'a> { /// matches meta_seq = ( COMMASEP(meta_item) ) fn parse_meta_seq(&mut self) -> Vec> { - self.parse_seq(&token::OpenDelim(token::Paren), + panictry!(self.parse_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_meta_item()).node + |p| Ok(p.parse_meta_item()))).node } fn parse_optional_meta(&mut self) -> Vec> { diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 277f5365db..bda01d5a65 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -63,7 +63,7 @@ pub fn strip_doc_comment_decoration(comment: &str) -> String { let mut i = 0; let mut j = lines.len(); // first line of all-stars should be omitted - if lines.len() > 0 && + if !lines.is_empty() && lines[0].chars().all(|c| c == '*') { i += 1; } @@ -294,7 +294,7 @@ fn read_block_comment(rdr: &mut StringReader, } } } - if curr_line.len() != 0 { + if !curr_line.is_empty() { trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col); diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 78470f0020..f891318659 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -116,7 +116,7 @@ impl<'a> Reader for TtReader<'a> { r } fn fatal(&self, m: &str) -> ! { - self.sp_diag.span_fatal(self.cur_span, m); + panic!(self.sp_diag.span_fatal(self.cur_span, m)); } fn err(&self, m: &str) { self.sp_diag.span_err(self.cur_span, m); @@ -181,7 +181,7 @@ impl<'a> StringReader<'a> { /// Report a fatal lexical error with a given span. pub fn fatal_span(&self, sp: Span, m: &str) -> ! { - self.span_diagnostic.span_fatal(sp, m) + panic!(self.span_diagnostic.span_fatal(sp, m)) } /// Report a lexical error with a given span. @@ -843,13 +843,19 @@ impl<'a> StringReader<'a> { if ascii_only { "unknown byte escape" } else { "unknown character escape" }, c); + let sp = codemap::mk_sp(escaped_pos, last_pos); if e == '\r' { - let sp = codemap::mk_sp(escaped_pos, last_pos); self.span_diagnostic.span_help( sp, "this is an isolated carriage return; consider checking \ your editor and version control settings") } + if (e == '{' || e == '}') && !ascii_only { + self.span_diagnostic.span_help( + sp, + "if used in a formatting string, \ + curly braces are escaped with `{{` and `}}`") + } false } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index f59e1d8214..f4b108c435 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,21 +12,22 @@ use ast; use codemap::{Span, CodeMap, FileMap}; -use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto}; +use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto, FatalError}; use parse::attr::ParserAttr; use parse::parser::Parser; use ptr::P; + use std::cell::{Cell, RefCell}; use std::fs::File; use std::io::Read; use std::iter; -#[allow(deprecated)] // Int -use std::num::Int; use std::path::{Path, PathBuf}; use std::rc::Rc; use std::str; +pub type PResult = Result; + #[macro_use] pub mod parser; @@ -88,7 +89,7 @@ pub fn parse_crate_from_file( cfg: ast::CrateConfig, sess: &ParseSess ) -> ast::Crate { - new_parser_from_file(sess, cfg, input).parse_crate_mod() + panictry!(new_parser_from_file(sess, cfg, input).parse_crate_mod()) // why is there no p.abort_if_errors here? } @@ -109,7 +110,7 @@ pub fn parse_crate_from_source_str(name: String, cfg, name, source); - maybe_aborted(p.parse_crate_mod(),p) + maybe_aborted(panictry!(p.parse_crate_mod()),p) } pub fn parse_crate_attrs_from_source_str(name: String, @@ -182,7 +183,7 @@ pub fn parse_tts_from_source_str(name: String, ); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. - maybe_aborted(p.parse_all_token_trees(),p) + maybe_aborted(panictry!(p.parse_all_token_trees()),p) } // Note: keep in sync with `with_hygiene::new_parser_from_source_str` @@ -245,7 +246,7 @@ pub fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option) -> Rc { let err = |msg: &str| { match spanopt { - Some(sp) => sess.span_diagnostic.span_fatal(sp, msg), + Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, msg)), None => sess.span_diagnostic.handler().fatal(msg), } }; @@ -286,7 +287,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) let cfg = Vec::new(); let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap); let mut p1 = Parser::new(sess, cfg, box srdr); - p1.parse_all_token_trees() + panictry!(p1.parse_all_token_trees()) } /// Given tts and cfg, produce a parser @@ -295,7 +296,7 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, cfg: ast::CrateConfig) -> Parser<'a> { let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts); let mut p = Parser::new(sess, cfg, box trdr); - p.check_unknown_macro_variable(); + panictry!(p.check_unknown_macro_variable()); p } @@ -325,7 +326,7 @@ pub mod with_hygiene { ); p.quote_depth += 1; // right now this is re-creating the token trees from ... token trees. - maybe_aborted(p.parse_all_token_trees(),p) + maybe_aborted(panictry!(p.parse_all_token_trees()),p) } // Note: keep this in sync with `super::new_parser_from_source_str` until @@ -358,7 +359,7 @@ pub mod with_hygiene { let cfg = Vec::new(); let srdr = make_reader(&sess.span_diagnostic, filemap); let mut p1 = Parser::new(sess, cfg, box srdr); - p1.parse_all_token_trees() + panictry!(p1.parse_all_token_trees()) } } @@ -711,8 +712,6 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> "u16" => ast::UnsignedIntLit(ast::TyU16), "u32" => ast::UnsignedIntLit(ast::TyU32), "u64" => ast::UnsignedIntLit(ast::TyU64), - "is" => ast::SignedIntLit(ast::TyIs, ast::Plus), - "us" => ast::UnsignedIntLit(ast::TyUs), _ => { // i and u look like widths, so lets // give an error message along those lines @@ -964,7 +963,7 @@ mod test { #[test] fn parse_ident_pat () { let sess = new_parse_sess(); let mut parser = string_to_parser(&sess, "b".to_string()); - assert!(parser.parse_pat() + assert!(panictry!(parser.parse_pat_nopanic()) == P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: ast::PatIdent(ast::BindByValue(ast::MutImmutable), diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index f120dde8e1..3b21b5059d 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -100,7 +100,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> { fn eat_obsolete_ident(&mut self, ident: &str) -> bool { if self.is_obsolete_ident(ident) { - self.bump(); + panictry!(self.bump()); true } else { false diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c721624323..0515d1ae94 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,8 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; -use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; -use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; +use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion}; +use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle}; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -74,6 +74,8 @@ use parse::{new_sub_parser_from_file, ParseSess}; use print::pprust; use ptr::P; use owned_slice::OwnedSlice; +use parse::PResult; +use diagnostic::FatalError; use std::collections::HashSet; use std::io::prelude::*; @@ -86,12 +88,10 @@ bitflags! { flags Restrictions: u8 { const UNRESTRICTED = 0b0000, const RESTRICTION_STMT_EXPR = 0b0001, - const RESTRICTION_NO_BAR_OP = 0b0010, - const RESTRICTION_NO_STRUCT_LITERAL = 0b0100, + const RESTRICTION_NO_STRUCT_LITERAL = 0b0010, } } - type ItemInfo = (Ident, Item_, Option >); /// How to parse a path. There are four different kinds of paths, all of which @@ -151,8 +151,8 @@ macro_rules! maybe_whole_expr { }; match found { Some(e) => { - $p.bump(); - return e; + try!($p.bump()); + return Ok(e); } None => () } @@ -166,12 +166,12 @@ macro_rules! maybe_whole { { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) + Some(try!(($p).bump_and_get())) } _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return x.clone(); + return Ok(x.clone()); } } ); @@ -179,12 +179,12 @@ macro_rules! maybe_whole { { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) + Some(try!(($p).bump_and_get())) } _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return x; + return Ok(x); } } ); @@ -192,12 +192,12 @@ macro_rules! maybe_whole { { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) + Some(try!(($p).bump_and_get())) } _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return (*x).clone(); + return Ok((*x).clone()); } } ); @@ -205,12 +205,12 @@ macro_rules! maybe_whole { { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) + Some(try!(($p).bump_and_get())) } _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return Some((*x).clone()); + return Ok(Some((*x).clone())); } } ); @@ -218,12 +218,12 @@ macro_rules! maybe_whole { { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { - Some(($p).bump_and_get()) + Some(try!(($p).bump_and_get())) } _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return (Vec::new(), x); + return Ok((Vec::new(), x)); } } ) @@ -339,6 +339,32 @@ impl<'a> Parser<'a> { } } + // Panicing fns (for now!) + // This is so that the quote_*!() syntax extensions + pub fn parse_expr(&mut self) -> P { + panictry!(self.parse_expr_nopanic()) + } + + pub fn parse_item(&mut self) -> Option> { + panictry!(self.parse_item_nopanic()) + } + + pub fn parse_pat(&mut self) -> P { + panictry!(self.parse_pat_nopanic()) + } + + pub fn parse_arm(&mut self) -> Arm { + panictry!(self.parse_arm_nopanic()) + } + + pub fn parse_ty(&mut self) -> P { + panictry!(self.parse_ty_nopanic()) + } + + pub fn parse_stmt(&mut self) -> Option> { + panictry!(self.parse_stmt_nopanic()) + } + /// Convert a token to a string using self's reader pub fn token_to_string(token: &token::Token) -> String { pprust::token_to_string(token) @@ -349,33 +375,35 @@ impl<'a> Parser<'a> { Parser::token_to_string(&self.token) } - pub fn unexpected_last(&self, t: &token::Token) -> ! { + pub fn unexpected_last(&self, t: &token::Token) -> FatalError { let token_str = Parser::token_to_string(t); let last_span = self.last_span; self.span_fatal(last_span, &format!("unexpected token: `{}`", - token_str)); + token_str)) } - pub fn unexpected(&mut self) -> ! { - self.expect_one_of(&[], &[]); - unreachable!() + pub fn unexpected(&mut self) -> FatalError { + match self.expect_one_of(&[], &[]) { + Err(e) => e, + Ok(_) => unreachable!() + } } /// Expect and consume the token t. Signal an error if /// the next token is not t. - pub fn expect(&mut self, t: &token::Token) { + pub fn expect(&mut self, t: &token::Token) -> PResult<()> { if self.expected_tokens.is_empty() { if self.token == *t { - self.bump(); + self.bump() } else { let token_str = Parser::token_to_string(t); let this_token_str = self.this_token_to_string(); - self.fatal(&format!("expected `{}`, found `{}`", + Err(self.fatal(&format!("expected `{}`, found `{}`", token_str, - this_token_str)) + this_token_str))) } } else { - self.expect_one_of(slice::ref_slice(t), &[]); + self.expect_one_of(slice::ref_slice(t), &[]) } } @@ -384,7 +412,7 @@ impl<'a> Parser<'a> { /// anything. Signal a fatal error if next token is unexpected. pub fn expect_one_of(&mut self, edible: &[token::Token], - inedible: &[token::Token]) { + inedible: &[token::Token]) -> PResult<()>{ fn tokens_to_string(tokens: &[TokenType]) -> String { let mut i = tokens.iter(); // This might be a sign we need a connect method on Iterator. @@ -403,9 +431,10 @@ impl<'a> Parser<'a> { }) } if edible.contains(&self.token) { - self.bump(); + self.bump() } else if inedible.contains(&self.token) { // leave it in the input + Ok(()) } else { let mut expected = edible.iter().map(|x| TokenType::Token(x.clone())) .collect::>(); @@ -415,12 +444,12 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - self.fatal( + Err(self.fatal( &(if expected.len() > 1 { (format!("expected one of {}, found `{}`", expect, actual)) - } else if expected.len() == 0 { + } else if expected.is_empty() { (format!("unexpected token: `{}`", actual)) } else { @@ -428,14 +457,16 @@ impl<'a> Parser<'a> { expect, actual)) })[..] - ) + )) } } /// Check for erroneous `ident { }`; if matches, signal error and /// recover (without consuming any expected input token). Returns /// true if and only if input was consumed for recovery. - pub fn check_for_erroneous_unit_struct_expecting(&mut self, expected: &[token::Token]) -> bool { + pub fn check_for_erroneous_unit_struct_expecting(&mut self, + expected: &[token::Token]) + -> PResult { if self.token == token::OpenDelim(token::Brace) && expected.iter().all(|t| *t != token::OpenDelim(token::Brace)) && self.look_ahead(1, |t| *t == token::CloseDelim(token::Brace)) { @@ -443,70 +474,72 @@ impl<'a> Parser<'a> { let span = self.span; self.span_err(span, "unit-like struct construction is written with no trailing `{ }`"); - self.eat(&token::OpenDelim(token::Brace)); - self.eat(&token::CloseDelim(token::Brace)); - true + try!(self.eat(&token::OpenDelim(token::Brace))); + try!(self.eat(&token::CloseDelim(token::Brace))); + Ok(true) } else { - false + Ok(false) } } /// Commit to parsing a complete expression `e` expected to be /// followed by some token from the set edible + inedible. Recover /// from anticipated input errors, discarding erroneous characters. - pub fn commit_expr(&mut self, e: &Expr, edible: &[token::Token], inedible: &[token::Token]) { + pub fn commit_expr(&mut self, e: &Expr, edible: &[token::Token], + inedible: &[token::Token]) -> PResult<()> { debug!("commit_expr {:?}", e); if let ExprPath(..) = e.node { // might be unit-struct construction; check for recoverableinput error. let mut expected = edible.iter().cloned().collect::>(); expected.push_all(inedible); - self.check_for_erroneous_unit_struct_expecting(&expected[..]); + try!(self.check_for_erroneous_unit_struct_expecting(&expected[..])); } self.expect_one_of(edible, inedible) } - pub fn commit_expr_expecting(&mut self, e: &Expr, edible: token::Token) { + pub fn commit_expr_expecting(&mut self, e: &Expr, edible: token::Token) -> PResult<()> { self.commit_expr(e, &[edible], &[]) } /// Commit to parsing a complete statement `s`, which expects to be /// followed by some token from the set edible + inedible. Check /// for recoverable input errors, discarding erroneous characters. - pub fn commit_stmt(&mut self, edible: &[token::Token], inedible: &[token::Token]) { + pub fn commit_stmt(&mut self, edible: &[token::Token], + inedible: &[token::Token]) -> PResult<()> { if self.last_token .as_ref() .map_or(false, |t| t.is_ident() || t.is_path()) { let mut expected = edible.iter().cloned().collect::>(); expected.push_all(&inedible); - self.check_for_erroneous_unit_struct_expecting(&expected); + try!(self.check_for_erroneous_unit_struct_expecting(&expected)); } self.expect_one_of(edible, inedible) } - pub fn commit_stmt_expecting(&mut self, edible: token::Token) { + pub fn commit_stmt_expecting(&mut self, edible: token::Token) -> PResult<()> { self.commit_stmt(&[edible], &[]) } - pub fn parse_ident(&mut self) -> ast::Ident { + pub fn parse_ident(&mut self) -> PResult { self.check_strict_keywords(); - self.check_reserved_keywords(); + try!(self.check_reserved_keywords()); match self.token { token::Ident(i, _) => { - self.bump(); - i + try!(self.bump()); + Ok(i) } token::Interpolated(token::NtIdent(..)) => { self.bug("ident interpolation not converted to real token"); } _ => { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected ident, found `{}`", - token_str)) + Err(self.fatal(&format!("expected ident, found `{}`", + token_str))) } } } - pub fn parse_ident_or_self_type(&mut self) -> ast::Ident { + pub fn parse_ident_or_self_type(&mut self) -> PResult { if self.is_self_type_ident() { self.expect_self_type_ident() } else { @@ -514,16 +547,16 @@ impl<'a> Parser<'a> { } } - pub fn parse_path_list_item(&mut self) -> ast::PathListItem { + pub fn parse_path_list_item(&mut self) -> PResult { let lo = self.span.lo; - let node = if self.eat_keyword(keywords::SelfValue) { + let node = if try!(self.eat_keyword(keywords::SelfValue)) { ast::PathListMod { id: ast::DUMMY_NODE_ID } } else { - let ident = self.parse_ident(); + let ident = try!(self.parse_ident()); ast::PathListIdent { name: ident, id: ast::DUMMY_NODE_ID } }; let hi = self.last_span.hi; - spanned(lo, hi, node) + Ok(spanned(lo, hi, node)) } /// Check if the next token is `tok`, and return `true` if so. @@ -538,10 +571,10 @@ impl<'a> Parser<'a> { /// Consume token 'tok' if it exists. Returns true if the given /// token was present, false otherwise. - pub fn eat(&mut self, tok: &token::Token) -> bool { + pub fn eat(&mut self, tok: &token::Token) -> PResult { let is_present = self.check(tok); - if is_present { self.bump() } - is_present + if is_present { try!(self.bump())} + Ok(is_present) } pub fn check_keyword(&mut self, kw: keywords::Keyword) -> bool { @@ -551,30 +584,32 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, eat it and return /// true. Otherwise, return false. - pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> bool { + pub fn eat_keyword(&mut self, kw: keywords::Keyword) -> PResult { if self.check_keyword(kw) { - self.bump(); - true + try!(self.bump()); + Ok(true) } else { - false + Ok(false) } } - pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> bool { + pub fn eat_keyword_noexpect(&mut self, kw: keywords::Keyword) -> PResult { if self.token.is_keyword(kw) { - self.bump(); - true + try!(self.bump()); + Ok(true) } else { - false + Ok(false) } } /// If the given word is not a keyword, signal an error. /// If the next token is not the given word, signal an error. /// Otherwise, eat it. - pub fn expect_keyword(&mut self, kw: keywords::Keyword) { - if !self.eat_keyword(kw) { - self.expect_one_of(&[], &[]); + pub fn expect_keyword(&mut self, kw: keywords::Keyword) -> PResult<()> { + if !try!(self.eat_keyword(kw) ){ + self.expect_one_of(&[], &[]) + } else { + Ok(()) } } @@ -590,28 +625,28 @@ impl<'a> Parser<'a> { } /// Signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&mut self) { + pub fn check_reserved_keywords(&mut self) -> PResult<()>{ if self.token.is_reserved_keyword() { let token_str = self.this_token_to_string(); - self.fatal(&format!("`{}` is a reserved keyword", - token_str)) + Err(self.fatal(&format!("`{}` is a reserved keyword", + token_str))) + } else { + Ok(()) } } /// Expect and consume an `&`. If `&&` is seen, replace it with a single /// `&` and continue. If an `&` is not seen, signal an error. - fn expect_and(&mut self) { + fn expect_and(&mut self) -> PResult<()> { self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); match self.token { token::BinOp(token::And) => self.bump(), token::AndAnd => { let span = self.span; let lo = span.lo + BytePos(1); - self.replace_token(token::BinOp(token::And), lo, span.hi) - } - _ => { - self.expect_one_of(&[], &[]); + Ok(self.replace_token(token::BinOp(token::And), lo, span.hi)) } + _ => self.expect_one_of(&[], &[]) } } @@ -634,54 +669,56 @@ impl<'a> Parser<'a> { /// /// This is meant to be used when parsing generics on a path to get the /// starting token. - fn eat_lt(&mut self) -> bool { + fn eat_lt(&mut self) -> PResult { self.expected_tokens.push(TokenType::Token(token::Lt)); match self.token { - token::Lt => { self.bump(); true } + token::Lt => { try!(self.bump()); Ok(true)} token::BinOp(token::Shl) => { let span = self.span; let lo = span.lo + BytePos(1); self.replace_token(token::Lt, lo, span.hi); - true + Ok(true) } - _ => false, + _ => Ok(false), } } - fn expect_lt(&mut self) { - if !self.eat_lt() { - self.expect_one_of(&[], &[]); + fn expect_lt(&mut self) -> PResult<()> { + if !try!(self.eat_lt()) { + self.expect_one_of(&[], &[]) + } else { + Ok(()) } } /// Expect and consume a GT. if a >> is seen, replace it /// with a single > and continue. If a GT is not seen, /// signal an error. - pub fn expect_gt(&mut self) { + pub fn expect_gt(&mut self) -> PResult<()> { self.expected_tokens.push(TokenType::Token(token::Gt)); match self.token { token::Gt => self.bump(), token::BinOp(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - self.replace_token(token::Gt, lo, span.hi) + Ok(self.replace_token(token::Gt, lo, span.hi)) } token::BinOpEq(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - self.replace_token(token::Ge, lo, span.hi) + Ok(self.replace_token(token::Ge, lo, span.hi)) } token::Ge => { let span = self.span; let lo = span.lo + BytePos(1); - self.replace_token(token::Eq, lo, span.hi) + Ok(self.replace_token(token::Eq, lo, span.hi)) } _ => { let gt_str = Parser::token_to_string(&token::Gt); let this_token_str = self.this_token_to_string(); - self.fatal(&format!("expected `{}`, found `{}`", + Err(self.fatal(&format!("expected `{}`, found `{}`", gt_str, - this_token_str)) + this_token_str))) } } } @@ -689,8 +726,8 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt_or_return(&mut self, sep: Option, mut f: F) - -> (OwnedSlice, bool) where - F: FnMut(&mut Parser) -> Option, + -> PResult<(OwnedSlice, bool)> where + F: FnMut(&mut Parser) -> PResult>, { let mut v = Vec::new(); // This loop works by alternating back and forth between parsing types @@ -708,15 +745,18 @@ impl<'a> Parser<'a> { } if i % 2 == 0 { - match f(self) { + match try!(f(self)) { Some(result) => v.push(result), - None => return (OwnedSlice::from_vec(v), true) + None => return Ok((OwnedSlice::from_vec(v), true)) } } else { - sep.as_ref().map(|t| self.expect(t)); + if let Some(t) = sep.as_ref() { + try!(self.expect(t)); + } + } } - return (OwnedSlice::from_vec(v), false); + return Ok((OwnedSlice::from_vec(v), false)); } /// Parse a sequence bracketed by '<' and '>', stopping @@ -724,36 +764,37 @@ impl<'a> Parser<'a> { pub fn parse_seq_to_before_gt(&mut self, sep: Option, mut f: F) - -> OwnedSlice where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { - let (result, returned) = self.parse_seq_to_before_gt_or_return(sep, |p| Some(f(p))); + let (result, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, + |p| Ok(Some(try!(f(p)))))); assert!(!returned); - return result; + return Ok(result); } pub fn parse_seq_to_gt(&mut self, sep: Option, f: F) - -> OwnedSlice where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { - let v = self.parse_seq_to_before_gt(sep, f); - self.expect_gt(); - return v; + let v = try!(self.parse_seq_to_before_gt(sep, f)); + try!(self.expect_gt()); + return Ok(v); } pub fn parse_seq_to_gt_or_return(&mut self, sep: Option, f: F) - -> (OwnedSlice, bool) where - F: FnMut(&mut Parser) -> Option, + -> PResult<(OwnedSlice, bool)> where + F: FnMut(&mut Parser) -> PResult>, { - let (v, returned) = self.parse_seq_to_before_gt_or_return(sep, f); + let (v, returned) = try!(self.parse_seq_to_before_gt_or_return(sep, f)); if !returned { - self.expect_gt(); + try!(self.expect_gt()); } - return (v, returned); + return Ok((v, returned)); } /// Parse a sequence, including the closing delimiter. The function @@ -763,12 +804,12 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> Vec where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { - let val = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - val + let val = try!(self.parse_seq_to_before_end(ket, sep, f)); + try!(self.bump()); + Ok(val) } /// Parse a sequence, not including the closing delimiter. The function @@ -778,8 +819,8 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, mut f: F) - -> Vec where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { let mut first: bool = true; let mut v = vec!(); @@ -787,14 +828,14 @@ impl<'a> Parser<'a> { match sep.sep { Some(ref t) => { if first { first = false; } - else { self.expect(t); } + else { try!(self.expect(t)); } } _ => () } if sep.trailing_sep_allowed && self.check(ket) { break; } - v.push(f(self)); + v.push(try!(f(self))); } - return v; + return Ok(v); } /// Parse a sequence, including the closing delimiter. The function @@ -805,13 +846,13 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> Vec where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); - result + try!(self.expect(bra)); + let result = try!(self.parse_seq_to_before_end(ket, sep, f)); + try!(self.bump()); + Ok(result) } /// Parse a sequence parameter of enum variant. For consistency purposes, @@ -821,16 +862,16 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> Vec where - F: FnMut(&mut Parser) -> T, + -> PResult> where + F: FnMut(&mut Parser) -> PResult, { - let result = self.parse_unspanned_seq(bra, ket, sep, f); + let result = try!(self.parse_unspanned_seq(bra, ket, sep, f)); if result.is_empty() { let last_span = self.last_span; self.span_err(last_span, "nullary enum variants are written with no trailing `( )`"); } - result + Ok(result) } // NB: Do not use this function unless you actually plan to place the @@ -840,19 +881,19 @@ impl<'a> Parser<'a> { ket: &token::Token, sep: SeqSep, f: F) - -> Spanned> where - F: FnMut(&mut Parser) -> T, + -> PResult>> where + F: FnMut(&mut Parser) -> PResult, { let lo = self.span.lo; - self.expect(bra); - let result = self.parse_seq_to_before_end(ket, sep, f); + try!(self.expect(bra)); + let result = try!(self.parse_seq_to_before_end(ket, sep, f)); let hi = self.span.hi; - self.bump(); - spanned(lo, hi, result) + try!(self.bump()); + Ok(spanned(lo, hi, result)) } /// Advance the parser by one token - pub fn bump(&mut self) { + pub fn bump(&mut self) -> PResult<()> { self.last_span = self.span; // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || self.token.is_path() { @@ -879,14 +920,14 @@ impl<'a> Parser<'a> { self.tokens_consumed += 1; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.check_unknown_macro_variable() } /// Advance the parser by one token and return the bumped token. - pub fn bump_and_get(&mut self) -> token::Token { + pub fn bump_and_get(&mut self) -> PResult { let old_token = mem::replace(&mut self.token, token::Underscore); - self.bump(); - old_token + try!(self.bump()); + Ok(old_token) } /// EFFECT: replace the current token and span with the given one @@ -914,16 +955,16 @@ impl<'a> Parser<'a> { } f(&self.buffer[((self.buffer_start + dist - 1) & 3) as usize].tok) } - pub fn fatal(&self, m: &str) -> ! { + pub fn fatal(&self, m: &str) -> diagnostic::FatalError { self.sess.span_diagnostic.span_fatal(self.span, m) } - pub fn span_fatal(&self, sp: Span, m: &str) -> ! { + pub fn span_fatal(&self, sp: Span, m: &str) -> diagnostic::FatalError { self.sess.span_diagnostic.span_fatal(sp, m) } - pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> ! { + pub fn span_fatal_help(&self, sp: Span, m: &str, help: &str) -> diagnostic::FatalError { self.span_err(sp, m); self.fileline_help(sp, help); - panic!(diagnostic::FatalError); + diagnostic::FatalError } pub fn span_note(&self, sp: Span, m: &str) { self.sess.span_diagnostic.span_note(sp, m) @@ -972,7 +1013,7 @@ impl<'a> Parser<'a> { } } - pub fn parse_for_in_type(&mut self) -> Ty_ { + pub fn parse_for_in_type(&mut self) -> PResult { /* Parses whatever can come after a `for` keyword in a type. The `for` has already been consumed. @@ -991,19 +1032,19 @@ impl<'a> Parser<'a> { // parse <'lt> let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs(); + let lifetime_defs = try!(self.parse_late_bound_lifetime_defs()); // examine next token to decide to do if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs) } else { let hi = self.span.hi; - let trait_ref = self.parse_trait_ref(); + let trait_ref = try!(self.parse_trait_ref()); let poly_trait_ref = ast::PolyTraitRef { bound_lifetimes: lifetime_defs, trait_ref: trait_ref, span: mk_sp(lo, hi)}; - let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds(BoundParsingMode::Bare) + let other_bounds = if try!(self.eat(&token::BinOp(token::Plus)) ){ + try!(self.parse_ty_param_bounds(BoundParsingMode::Bare)) } else { OwnedSlice::empty() }; @@ -1011,16 +1052,16 @@ impl<'a> Parser<'a> { Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() .chain(other_bounds.into_vec().into_iter()) .collect(); - ast::TyPolyTraitRef(all_bounds) + Ok(ast::TyPolyTraitRef(all_bounds)) } } - pub fn parse_ty_path(&mut self) -> Ty_ { - TyPath(None, self.parse_path(LifetimeAndTypesWithoutColons)) + pub fn parse_ty_path(&mut self) -> PResult { + Ok(TyPath(None, try!(self.parse_path(LifetimeAndTypesWithoutColons)))) } /// parse a TyBareFn type: - pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> Ty_ { + pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult { /* [unsafe] [extern "ABI"] fn <'lt> (S) -> T @@ -1033,68 +1074,69 @@ impl<'a> Parser<'a> { Function Style */ - let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(keywords::Extern) { - self.parse_opt_abi().unwrap_or(abi::C) + let unsafety = try!(self.parse_unsafety()); + let abi = if try!(self.eat_keyword(keywords::Extern) ){ + try!(self.parse_opt_abi()).unwrap_or(abi::C) } else { abi::Rust }; - self.expect_keyword(keywords::Fn); - let (inputs, variadic) = self.parse_fn_args(false, true); - let ret_ty = self.parse_ret_ty(); + try!(self.expect_keyword(keywords::Fn)); + let (inputs, variadic) = try!(self.parse_fn_args(false, true)); + let ret_ty = try!(self.parse_ret_ty()); let decl = P(FnDecl { inputs: inputs, output: ret_ty, variadic: variadic }); - TyBareFn(P(BareFnTy { + Ok(TyBareFn(P(BareFnTy { abi: abi, unsafety: unsafety, lifetimes: lifetime_defs, decl: decl - })) + }))) } /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`). - pub fn parse_obsolete_closure_kind(&mut self) { + pub fn parse_obsolete_closure_kind(&mut self) -> PResult<()> { let lo = self.span.lo; if self.check(&token::BinOp(token::And)) && self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && self.look_ahead(2, |t| *t == token::Colon) { - self.bump(); - self.bump(); - self.bump(); + try!(self.bump()); + try!(self.bump()); + try!(self.bump()); } else if self.token == token::BinOp(token::And) && self.look_ahead(1, |t| *t == token::Colon) { - self.bump(); - self.bump(); + try!(self.bump()); + try!(self.bump()); } else if - self.eat(&token::Colon) + try!(self.eat(&token::Colon)) { /* nothing */ } else { - return; + return Ok(()); } - let span = mk_sp(lo, self.span.hi); - self.obsolete(span, ObsoleteSyntax::ClosureKind); + let span = mk_sp(lo, self.span.hi); + self.obsolete(span, ObsoleteSyntax::ClosureKind); + Ok(()) } - pub fn parse_unsafety(&mut self) -> Unsafety { - if self.eat_keyword(keywords::Unsafe) { - return Unsafety::Unsafe; + pub fn parse_unsafety(&mut self) -> PResult { + if try!(self.eat_keyword(keywords::Unsafe)) { + return Ok(Unsafety::Unsafe); } else { - return Unsafety::Normal; + return Ok(Unsafety::Normal); } } /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> Vec> { + pub fn parse_trait_items(&mut self) -> PResult>> { self.parse_unspanned_seq( &token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), @@ -1103,30 +1145,30 @@ impl<'a> Parser<'a> { let lo = p.span.lo; let mut attrs = p.parse_outer_attributes(); - let (name, node) = if p.eat_keyword(keywords::Type) { - let TyParam {ident, bounds, default, ..} = p.parse_ty_param(); - p.expect(&token::Semi); + let (name, node) = if try!(p.eat_keyword(keywords::Type)) { + let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param()); + try!(p.expect(&token::Semi)); (ident, TypeTraitItem(bounds, default)) } else { - let style = p.parse_unsafety(); - let abi = if p.eat_keyword(keywords::Extern) { - p.parse_opt_abi().unwrap_or(abi::C) + let style = try!(p.parse_unsafety()); + let abi = if try!(p.eat_keyword(keywords::Extern)) { + try!(p.parse_opt_abi()).unwrap_or(abi::C) } else { abi::Rust }; - p.expect_keyword(keywords::Fn); + try!(p.expect_keyword(keywords::Fn)); - let ident = p.parse_ident(); - let mut generics = p.parse_generics(); + let ident = try!(p.parse_ident()); + let mut generics = try!(p.parse_generics()); - let (explicit_self, d) = p.parse_fn_decl_with_self(|p| { + let (explicit_self, d) = try!(p.parse_fn_decl_with_self(|p|{ // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... p.parse_arg_general(false) - }); + })); - generics.where_clause = p.parse_where_clause(); + generics.where_clause = try!(p.parse_where_clause()); let sig = ast::MethodSig { unsafety: style, decl: d, @@ -1137,72 +1179,72 @@ impl<'a> Parser<'a> { let body = match p.token { token::Semi => { - p.bump(); + try!(p.bump()); debug!("parse_trait_methods(): parsing required method"); None } token::OpenDelim(token::Brace) => { debug!("parse_trait_methods(): parsing provided method"); let (inner_attrs, body) = - p.parse_inner_attrs_and_block(); + try!(p.parse_inner_attrs_and_block()); attrs.push_all(&inner_attrs[..]); Some(body) } _ => { let token_str = p.this_token_to_string(); - p.fatal(&format!("expected `;` or `{{`, found `{}`", - token_str)[..]) + return Err(p.fatal(&format!("expected `;` or `{{`, found `{}`", + token_str)[..])) } }; (ident, ast::MethodTraitItem(sig, body)) }; - P(TraitItem { + Ok(P(TraitItem { id: ast::DUMMY_NODE_ID, ident: name, attrs: attrs, node: node, span: mk_sp(lo, p.last_span.hi), - }) + })) }) } /// Parse a possibly mutable type - pub fn parse_mt(&mut self) -> MutTy { - let mutbl = self.parse_mutability(); - let t = self.parse_ty(); - MutTy { ty: t, mutbl: mutbl } + pub fn parse_mt(&mut self) -> PResult { + let mutbl = try!(self.parse_mutability()); + let t = try!(self.parse_ty_nopanic()); + Ok(MutTy { ty: t, mutbl: mutbl }) } /// Parse optional return type [ -> TY ] in function decl - pub fn parse_ret_ty(&mut self) -> FunctionRetTy { - if self.eat(&token::RArrow) { - if self.eat(&token::Not) { - NoReturn(self.span) + pub fn parse_ret_ty(&mut self) -> PResult { + if try!(self.eat(&token::RArrow) ){ + if try!(self.eat(&token::Not) ){ + Ok(NoReturn(self.span)) } else { - Return(self.parse_ty()) + Ok(Return(try!(self.parse_ty_nopanic()))) } } else { let pos = self.span.lo; - DefaultReturn(mk_sp(pos, pos)) + Ok(DefaultReturn(mk_sp(pos, pos))) } } /// Parse a type in a context where `T1+T2` is allowed. - pub fn parse_ty_sum(&mut self) -> P { + pub fn parse_ty_sum(&mut self) -> PResult> { let lo = self.span.lo; - let lhs = self.parse_ty(); + let lhs = try!(self.parse_ty_nopanic()); - if !self.eat(&token::BinOp(token::Plus)) { - return lhs; + if !try!(self.eat(&token::BinOp(token::Plus)) ){ + return Ok(lhs); } - let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); + let bounds = try!(self.parse_ty_param_bounds(BoundParsingMode::Bare)); // In type grammar, `+` is treated like a binary operator, // and hence both L and R side are required. - if bounds.len() == 0 { + if bounds.is_empty() { let last_span = self.last_span; self.span_err(last_span, "at least one type parameter bound \ @@ -1211,17 +1253,17 @@ impl<'a> Parser<'a> { let sp = mk_sp(lo, self.last_span.hi); let sum = ast::TyObjectSum(lhs, bounds); - P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp}) + Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) } /// Parse a type. - pub fn parse_ty(&mut self) -> P { + pub fn parse_ty_nopanic(&mut self) -> PResult> { maybe_whole!(no_clone self, NtTy); let lo = self.span.lo; let t = if self.check(&token::OpenDelim(token::Paren)) { - self.bump(); + try!(self.bump()); // (t) is a parenthesized ty // (t,) is the type of a tuple with only one field, @@ -1229,17 +1271,17 @@ impl<'a> Parser<'a> { let mut ts = vec![]; let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty_sum()); + ts.push(try!(self.parse_ty_sum())); if self.check(&token::Comma) { last_comma = true; - self.bump(); + try!(self.bump()); } else { last_comma = false; break; } } - self.expect(&token::CloseDelim(token::Paren)); + try!(self.expect(&token::CloseDelim(token::Paren))); if ts.len() == 1 && !last_comma { TyParen(ts.into_iter().nth(0).unwrap()) } else { @@ -1247,44 +1289,44 @@ impl<'a> Parser<'a> { } } else if self.check(&token::BinOp(token::Star)) { // STAR POINTER (bare pointer?) - self.bump(); - TyPtr(self.parse_ptr()) + try!(self.bump()); + TyPtr(try!(self.parse_ptr())) } else if self.check(&token::OpenDelim(token::Bracket)) { // VECTOR - self.expect(&token::OpenDelim(token::Bracket)); - let t = self.parse_ty_sum(); + try!(self.expect(&token::OpenDelim(token::Bracket))); + let t = try!(self.parse_ty_sum()); // Parse the `; e` in `[ i32; e ]` // where `e` is a const expression - let t = match self.maybe_parse_fixed_length_of_vec() { + let t = match try!(self.maybe_parse_fixed_length_of_vec()) { None => TyVec(t), Some(suffix) => TyFixedLengthVec(t, suffix) }; - self.expect(&token::CloseDelim(token::Bracket)); + try!(self.expect(&token::CloseDelim(token::Bracket))); t } else if self.check(&token::BinOp(token::And)) || self.token == token::AndAnd { // BORROWED POINTER - self.expect_and(); - self.parse_borrowed_pointee() + try!(self.expect_and()); + try!(self.parse_borrowed_pointee()) } else if self.check_keyword(keywords::For) { - self.parse_for_in_type() + try!(self.parse_for_in_type()) } else if self.token_is_bare_fn_keyword() { // BARE FUNCTION - self.parse_ty_bare_fn(Vec::new()) - } else if self.eat_keyword_noexpect(keywords::Typeof) { + try!(self.parse_ty_bare_fn(Vec::new())) + } else if try!(self.eat_keyword_noexpect(keywords::Typeof)) { // TYPEOF // In order to not be ambiguous, the type must be surrounded by parens. - self.expect(&token::OpenDelim(token::Paren)); - let e = self.parse_expr(); - self.expect(&token::CloseDelim(token::Paren)); + try!(self.expect(&token::OpenDelim(token::Paren))); + let e = try!(self.parse_expr_nopanic()); + try!(self.expect(&token::CloseDelim(token::Paren))); TyTypeof(e) - } else if self.eat_lt() { + } else if try!(self.eat_lt()) { // QUALIFIED PATH `::item` - let self_type = self.parse_ty_sum(); + let self_type = try!(self.parse_ty_sum()); - let mut path = if self.eat_keyword(keywords::As) { - self.parse_path(LifetimeAndTypesWithoutColons) + let mut path = if try!(self.eat_keyword(keywords::As) ){ + try!(self.parse_path(LifetimeAndTypesWithoutColons)) } else { ast::Path { span: self.span, @@ -1298,11 +1340,11 @@ impl<'a> Parser<'a> { position: path.segments.len() }; - self.expect(&token::Gt); - self.expect(&token::ModSep); + try!(self.expect(&token::Gt)); + try!(self.expect(&token::ModSep)); path.segments.push(ast::PathSegment { - identifier: self.parse_ident(), + identifier: try!(self.parse_ident()), parameters: ast::PathParameters::none() }); @@ -1316,32 +1358,32 @@ impl<'a> Parser<'a> { self.token.is_ident() || self.token.is_path() { // NAMED TYPE - self.parse_ty_path() - } else if self.eat(&token::Underscore) { + try!(self.parse_ty_path()) + } else if try!(self.eat(&token::Underscore) ){ // TYPE TO BE INFERRED TyInfer } else { let this_token_str = self.this_token_to_string(); let msg = format!("expected type, found `{}`", this_token_str); - self.fatal(&msg[..]); + return Err(self.fatal(&msg[..])); }; let sp = mk_sp(lo, self.last_span.hi); - P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp}) + Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) } - pub fn parse_borrowed_pointee(&mut self) -> Ty_ { + pub fn parse_borrowed_pointee(&mut self) -> PResult { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.parse_opt_lifetime(); + let opt_lifetime = try!(self.parse_opt_lifetime()); - let mt = self.parse_mt(); - return TyRptr(opt_lifetime, mt); + let mt = try!(self.parse_mt()); + return Ok(TyRptr(opt_lifetime, mt)); } - pub fn parse_ptr(&mut self) -> MutTy { - let mutbl = if self.eat_keyword(keywords::Mut) { + pub fn parse_ptr(&mut self) -> PResult { + let mutbl = if try!(self.eat_keyword(keywords::Mut) ){ MutMutable - } else if self.eat_keyword(keywords::Const) { + } else if try!(self.eat_keyword(keywords::Const) ){ MutImmutable } else { let span = self.last_span; @@ -1351,8 +1393,8 @@ impl<'a> Parser<'a> { known as `*const T`"); MutImmutable }; - let t = self.parse_ty(); - MutTy { ty: t, mutbl: mutbl } + let t = try!(self.parse_ty_nopanic()); + Ok(MutTy { ty: t, mutbl: mutbl }) } pub fn is_named_argument(&mut self) -> bool { @@ -1376,13 +1418,13 @@ impl<'a> Parser<'a> { /// This version of parse arg doesn't necessarily require /// identifier names. - pub fn parse_arg_general(&mut self, require_name: bool) -> Arg { + pub fn parse_arg_general(&mut self, require_name: bool) -> PResult { let pat = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{})", require_name); - let pat = self.parse_pat(); + let pat = try!(self.parse_pat_nopanic()); - self.expect(&token::Colon); + try!(self.expect(&token::Colon)); pat } else { debug!("parse_arg_general ident_to_pat"); @@ -1391,25 +1433,25 @@ impl<'a> Parser<'a> { special_idents::invalid) }; - let t = self.parse_ty_sum(); + let t = try!(self.parse_ty_sum()); - Arg { + Ok(Arg { ty: t, pat: pat, id: ast::DUMMY_NODE_ID, - } + }) } /// Parse a single function argument - pub fn parse_arg(&mut self) -> Arg { + pub fn parse_arg(&mut self) -> PResult { self.parse_arg_general(true) } /// Parse an argument in a lambda header e.g. |arg, arg| - pub fn parse_fn_block_arg(&mut self) -> Arg { - let pat = self.parse_pat(); - let t = if self.eat(&token::Colon) { - self.parse_ty_sum() + pub fn parse_fn_block_arg(&mut self) -> PResult { + let pat = try!(self.parse_pat_nopanic()); + let t = if try!(self.eat(&token::Colon) ){ + try!(self.parse_ty_sum()) } else { P(Ty { id: ast::DUMMY_NODE_ID, @@ -1417,29 +1459,29 @@ impl<'a> Parser<'a> { span: mk_sp(self.span.lo, self.span.hi), }) }; - Arg { + Ok(Arg { ty: t, pat: pat, id: ast::DUMMY_NODE_ID - } + }) } - pub fn maybe_parse_fixed_length_of_vec(&mut self) -> Option> { + pub fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult>> { if self.check(&token::Semi) { - self.bump(); - Some(self.parse_expr()) + try!(self.bump()); + Ok(Some(try!(self.parse_expr_nopanic()))) } else { - None + Ok(None) } } /// Matches token_lit = LIT_INTEGER | ... - pub fn lit_from_token(&self, tok: &token::Token) -> Lit_ { + pub fn lit_from_token(&self, tok: &token::Token) -> PResult { match *tok { token::Interpolated(token::NtExpr(ref v)) => { match v.node { - ExprLit(ref lit) => { lit.node.clone() } - _ => { self.unexpected_last(tok); } + ExprLit(ref lit) => { Ok(lit.node.clone()) } + _ => { return Err(self.unexpected_last(tok)); } } } token::Literal(lit, suf) => { @@ -1486,43 +1528,43 @@ impl<'a> Parser<'a> { self.expect_no_suffix(sp, &*format!("{} literal", lit.short_name()), suf) } - out + Ok(out) } - _ => { self.unexpected_last(tok); } + _ => { return Err(self.unexpected_last(tok)); } } } /// Matches lit = true | false | token_lit - pub fn parse_lit(&mut self) -> Lit { + pub fn parse_lit(&mut self) -> PResult { let lo = self.span.lo; - let lit = if self.eat_keyword(keywords::True) { + let lit = if try!(self.eat_keyword(keywords::True) ){ LitBool(true) - } else if self.eat_keyword(keywords::False) { + } else if try!(self.eat_keyword(keywords::False) ){ LitBool(false) } else { - let token = self.bump_and_get(); - let lit = self.lit_from_token(&token); + let token = try!(self.bump_and_get()); + let lit = try!(self.lit_from_token(&token)); lit }; - codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) } + Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) }) } /// matches '-' lit | lit - pub fn parse_literal_maybe_minus(&mut self) -> P { + pub fn parse_literal_maybe_minus(&mut self) -> PResult> { let minus_lo = self.span.lo; - let minus_present = self.eat(&token::BinOp(token::Minus)); + let minus_present = try!(self.eat(&token::BinOp(token::Minus))); let lo = self.span.lo; - let literal = P(self.parse_lit()); + let literal = P(try!(self.parse_lit())); let hi = self.span.hi; let expr = self.mk_expr(lo, hi, ExprLit(literal)); if minus_present { let minus_hi = self.span.hi; let unary = self.mk_unary(UnNeg, expr); - self.mk_expr(minus_lo, minus_hi, unary) + Ok(self.mk_expr(minus_lo, minus_hi, unary)) } else { - expr + Ok(expr) } } @@ -1530,31 +1572,31 @@ impl<'a> Parser<'a> { /// mode. The `mode` parameter determines whether lifetimes, types, and/or /// bounds are permitted and whether `::` must precede type parameter /// groups. - pub fn parse_path(&mut self, mode: PathParsingMode) -> ast::Path { + pub fn parse_path(&mut self, mode: PathParsingMode) -> PResult { // Check for a whole path... let found = match self.token { - token::Interpolated(token::NtPath(_)) => Some(self.bump_and_get()), + token::Interpolated(token::NtPath(_)) => Some(try!(self.bump_and_get())), _ => None, }; if let Some(token::Interpolated(token::NtPath(box path))) = found { - return path; + return Ok(path); } let lo = self.span.lo; - let is_global = self.eat(&token::ModSep); + let is_global = try!(self.eat(&token::ModSep)); // Parse any number of segments and bound sets. A segment is an // identifier followed by an optional lifetime and a set of types. // A bound set is a set of type parameter bounds. let segments = match mode { LifetimeAndTypesWithoutColons => { - self.parse_path_segments_without_colons() + try!(self.parse_path_segments_without_colons()) } LifetimeAndTypesWithColons => { - self.parse_path_segments_with_colons() + try!(self.parse_path_segments_with_colons()) } NoTypesAllowed => { - self.parse_path_segments_without_types() + try!(self.parse_path_segments_without_types()) } }; @@ -1562,42 +1604,42 @@ impl<'a> Parser<'a> { let span = mk_sp(lo, self.last_span.hi); // Assemble the result. - ast::Path { + Ok(ast::Path { span: span, global: is_global, segments: segments, - } + }) } /// Examples: /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> Vec { + pub fn parse_path_segments_without_colons(&mut self) -> PResult> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident_or_self_type(); + let identifier = try!(self.parse_ident_or_self_type()); // Parse types, optionally. - let parameters = if self.eat_lt() { - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt(); + let parameters = if try!(self.eat_lt() ){ + let (lifetimes, types, bindings) = try!(self.parse_generic_values_after_lt()); ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, types: OwnedSlice::from_vec(types), bindings: OwnedSlice::from_vec(bindings), }) - } else if self.eat(&token::OpenDelim(token::Paren)) { + } else if try!(self.eat(&token::OpenDelim(token::Paren)) ){ let lo = self.last_span.lo; - let inputs = self.parse_seq_to_end( + let inputs = try!(self.parse_seq_to_end( &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_ty_sum()); + |p| p.parse_ty_sum())); - let output_ty = if self.eat(&token::RArrow) { - Some(self.parse_ty()) + let output_ty = if try!(self.eat(&token::RArrow) ){ + Some(try!(self.parse_ty_nopanic())) } else { None }; @@ -1618,33 +1660,33 @@ impl<'a> Parser<'a> { parameters: parameters }); // Continue only if we see a `::` - if !self.eat(&token::ModSep) { - return segments; + if !try!(self.eat(&token::ModSep) ){ + return Ok(segments); } } } /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> Vec { + pub fn parse_path_segments_with_colons(&mut self) -> PResult> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident_or_self_type(); + let identifier = try!(self.parse_ident_or_self_type()); // If we do not see a `::`, stop. - if !self.eat(&token::ModSep) { + if !try!(self.eat(&token::ModSep) ){ segments.push(ast::PathSegment { identifier: identifier, parameters: ast::PathParameters::none() }); - return segments; + return Ok(segments); } // Check for a type segment. - if self.eat_lt() { + if try!(self.eat_lt() ){ // Consumed `a::b::<`, go look for types - let (lifetimes, types, bindings) = self.parse_generic_values_after_lt(); + let (lifetimes, types, bindings) = try!(self.parse_generic_values_after_lt()); segments.push(ast::PathSegment { identifier: identifier, parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { @@ -1655,8 +1697,8 @@ impl<'a> Parser<'a> { }); // Consumed `a::b::`, check for `::` before proceeding - if !self.eat(&token::ModSep) { - return segments; + if !try!(self.eat(&token::ModSep) ){ + return Ok(segments); } } else { // Consumed `a::`, go look for `b` @@ -1671,11 +1713,11 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` - pub fn parse_path_segments_without_types(&mut self) -> Vec { + pub fn parse_path_segments_without_types(&mut self) -> PResult> { let mut segments = Vec::new(); loop { // First, parse an identifier. - let identifier = self.parse_ident_or_self_type(); + let identifier = try!(self.parse_ident_or_self_type()); // Assemble and push the result. segments.push(ast::PathSegment { @@ -1684,55 +1726,55 @@ impl<'a> Parser<'a> { }); // If we do not see a `::`, stop. - if !self.eat(&token::ModSep) { - return segments; + if !try!(self.eat(&token::ModSep) ){ + return Ok(segments); } } } /// parses 0 or 1 lifetime - pub fn parse_opt_lifetime(&mut self) -> Option { + pub fn parse_opt_lifetime(&mut self) -> PResult> { match self.token { token::Lifetime(..) => { - Some(self.parse_lifetime()) + Ok(Some(try!(self.parse_lifetime()))) } _ => { - None + Ok(None) } } } /// Parses a single lifetime /// Matches lifetime = LIFETIME - pub fn parse_lifetime(&mut self) -> ast::Lifetime { + pub fn parse_lifetime(&mut self) -> PResult { match self.token { token::Lifetime(i) => { let span = self.span; - self.bump(); - return ast::Lifetime { + try!(self.bump()); + return Ok(ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, name: i.name - }; + }); } _ => { - self.fatal(&format!("expected a lifetime name")); + return Err(self.fatal(&format!("expected a lifetime name"))); } } } /// Parses `lifetime_defs = [ lifetime_defs { ',' lifetime_defs } ]` where `lifetime_def = /// lifetime [':' lifetimes]` - pub fn parse_lifetime_defs(&mut self) -> Vec { + pub fn parse_lifetime_defs(&mut self) -> PResult> { let mut res = Vec::new(); loop { match self.token { token::Lifetime(_) => { - let lifetime = self.parse_lifetime(); + let lifetime = try!(self.parse_lifetime()); let bounds = - if self.eat(&token::Colon) { - self.parse_lifetimes(token::BinOp(token::Plus)) + if try!(self.eat(&token::Colon) ){ + try!(self.parse_lifetimes(token::BinOp(token::Plus))) } else { Vec::new() }; @@ -1741,20 +1783,20 @@ impl<'a> Parser<'a> { } _ => { - return res; + return Ok(res); } } match self.token { - token::Comma => { self.bump(); } - token::Gt => { return res; } - token::BinOp(token::Shr) => { return res; } + token::Comma => { try!(self.bump());} + token::Gt => { return Ok(res); } + token::BinOp(token::Shr) => { return Ok(res); } _ => { let this_token_str = self.this_token_to_string(); let msg = format!("expected `,` or `>` after lifetime \ name, found `{}`", this_token_str); - self.fatal(&msg[..]); + return Err(self.fatal(&msg[..])); } } } @@ -1766,48 +1808,48 @@ impl<'a> Parser<'a> { /// Parses zero or more comma separated lifetimes. Expects each lifetime to be followed by /// either a comma or `>`. Used when parsing type parameter lists, where we expect something /// like `<'a, 'b, T>`. - pub fn parse_lifetimes(&mut self, sep: token::Token) -> Vec { + pub fn parse_lifetimes(&mut self, sep: token::Token) -> PResult> { let mut res = Vec::new(); loop { match self.token { token::Lifetime(_) => { - res.push(self.parse_lifetime()); + res.push(try!(self.parse_lifetime())); } _ => { - return res; + return Ok(res); } } if self.token != sep { - return res; + return Ok(res); } - self.bump(); + try!(self.bump()); } } /// Parse mutability declaration (mut/const/imm) - pub fn parse_mutability(&mut self) -> Mutability { - if self.eat_keyword(keywords::Mut) { - MutMutable + pub fn parse_mutability(&mut self) -> PResult { + if try!(self.eat_keyword(keywords::Mut) ){ + Ok(MutMutable) } else { - MutImmutable + Ok(MutImmutable) } } /// Parse ident COLON expr - pub fn parse_field(&mut self) -> Field { + pub fn parse_field(&mut self) -> PResult { let lo = self.span.lo; - let i = self.parse_ident(); + let i = try!(self.parse_ident()); let hi = self.last_span.hi; - self.expect(&token::Colon); - let e = self.parse_expr(); - ast::Field { + try!(self.expect(&token::Colon)); + let e = try!(self.parse_expr_nopanic()); + Ok(ast::Field { ident: spanned(lo, hi, i), span: mk_sp(lo, e.span.hi), expr: e, - } + }) } pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: Expr_) -> P { @@ -1884,21 +1926,21 @@ impl<'a> Parser<'a> { }) } - fn expect_open_delim(&mut self) -> token::DelimToken { + fn expect_open_delim(&mut self) -> PResult { self.expected_tokens.push(TokenType::Token(token::Gt)); match self.token { token::OpenDelim(delim) => { - self.bump(); - delim + try!(self.bump()); + Ok(delim) }, - _ => self.fatal("expected open delimiter"), + _ => Err(self.fatal("expected open delimiter")), } } /// At the bottom (top?) of the precedence hierarchy, /// parse things like parenthesized exprs, /// macros, return, etc. - pub fn parse_bottom_expr(&mut self) -> P { + pub fn parse_bottom_expr(&mut self) -> PResult> { maybe_whole_expr!(self); let lo = self.span.lo; @@ -1909,32 +1951,32 @@ impl<'a> Parser<'a> { // Note: when adding new syntax here, don't forget to adjust Token::can_begin_expr(). match self.token { token::OpenDelim(token::Paren) => { - self.bump(); + try!(self.bump()); // (e) is parenthesized e // (e,) is a tuple with only one field, e let mut es = vec![]; let mut trailing_comma = false; while self.token != token::CloseDelim(token::Paren) { - es.push(self.parse_expr()); - self.commit_expr(&**es.last().unwrap(), &[], - &[token::Comma, token::CloseDelim(token::Paren)]); + es.push(try!(self.parse_expr_nopanic())); + try!(self.commit_expr(&**es.last().unwrap(), &[], + &[token::Comma, token::CloseDelim(token::Paren)])); if self.check(&token::Comma) { trailing_comma = true; - self.bump(); + try!(self.bump()); } else { trailing_comma = false; break; } } - self.bump(); + try!(self.bump()); - hi = self.span.hi; + hi = self.last_span.hi; return if es.len() == 1 && !trailing_comma { - self.mk_expr(lo, hi, ExprParen(es.into_iter().nth(0).unwrap())) + Ok(self.mk_expr(lo, hi, ExprParen(es.into_iter().nth(0).unwrap()))) } else { - self.mk_expr(lo, hi, ExprTup(es)) + Ok(self.mk_expr(lo, hi, ExprTup(es))) } }, token::OpenDelim(token::Brace) => { @@ -1947,52 +1989,52 @@ impl<'a> Parser<'a> { name: token::SELF_KEYWORD_NAME, ctxt: _ }, token::Plain) => { - self.bump(); + try!(self.bump()); let path = ast_util::ident_to_path(mk_sp(lo, hi), id); ex = ExprPath(None, path); hi = self.last_span.hi; } token::OpenDelim(token::Bracket) => { - self.bump(); + try!(self.bump()); if self.check(&token::CloseDelim(token::Bracket)) { // Empty vector. - self.bump(); + try!(self.bump()); ex = ExprVec(Vec::new()); } else { // Nonempty vector. - let first_expr = self.parse_expr(); + let first_expr = try!(self.parse_expr_nopanic()); if self.check(&token::Semi) { // Repeating vector syntax: [ 0; 512 ] - self.bump(); - let count = self.parse_expr(); - self.expect(&token::CloseDelim(token::Bracket)); + try!(self.bump()); + let count = try!(self.parse_expr_nopanic()); + try!(self.expect(&token::CloseDelim(token::Bracket))); ex = ExprRepeat(first_expr, count); } else if self.check(&token::Comma) { // Vector with two or more elements. - self.bump(); - let remaining_exprs = self.parse_seq_to_end( + try!(self.bump()); + let remaining_exprs = try!(self.parse_seq_to_end( &token::CloseDelim(token::Bracket), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_expr() - ); + |p| Ok(try!(p.parse_expr_nopanic())) + )); let mut exprs = vec!(first_expr); exprs.extend(remaining_exprs.into_iter()); ex = ExprVec(exprs); } else { // Vector with one element. - self.expect(&token::CloseDelim(token::Bracket)); + try!(self.expect(&token::CloseDelim(token::Bracket))); ex = ExprVec(vec!(first_expr)); } } hi = self.last_span.hi; } _ => { - if self.eat_lt() { + if try!(self.eat_lt()){ // QUALIFIED PATH `::item::<'a, T>` - let self_type = self.parse_ty_sum(); - let mut path = if self.eat_keyword(keywords::As) { - self.parse_path(LifetimeAndTypesWithoutColons) + let self_type = try!(self.parse_ty_sum()); + let mut path = if try!(self.eat_keyword(keywords::As) ){ + try!(self.parse_path(LifetimeAndTypesWithoutColons)) } else { ast::Path { span: self.span, @@ -2004,15 +2046,15 @@ impl<'a> Parser<'a> { ty: self_type, position: path.segments.len() }; - self.expect(&token::Gt); - self.expect(&token::ModSep); + try!(self.expect(&token::Gt)); + try!(self.expect(&token::ModSep)); - let item_name = self.parse_ident(); - let parameters = if self.eat(&token::ModSep) { - self.expect_lt(); + let item_name = try!(self.parse_ident()); + let parameters = if try!(self.eat(&token::ModSep) ){ + try!(self.expect_lt()); // Consumed `item::<`, go look for types let (lifetimes, types, bindings) = - self.parse_generic_values_after_lt(); + try!(self.parse_generic_values_after_lt()); ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: lifetimes, types: OwnedSlice::from_vec(types), @@ -2032,72 +2074,72 @@ impl<'a> Parser<'a> { path.span.hi = self.last_span.hi; let hi = self.span.hi; - return self.mk_expr(lo, hi, ExprPath(Some(qself), path)); + return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } - if self.eat_keyword(keywords::Move) { + if try!(self.eat_keyword(keywords::Move) ){ return self.parse_lambda_expr(CaptureByValue); } - if self.eat_keyword(keywords::If) { + if try!(self.eat_keyword(keywords::If)) { return self.parse_if_expr(); } - if self.eat_keyword(keywords::For) { + if try!(self.eat_keyword(keywords::For) ){ return self.parse_for_expr(None); } - if self.eat_keyword(keywords::While) { + if try!(self.eat_keyword(keywords::While) ){ return self.parse_while_expr(None); } if self.token.is_lifetime() { let lifetime = self.get_lifetime(); - self.bump(); - self.expect(&token::Colon); - if self.eat_keyword(keywords::While) { + try!(self.bump()); + try!(self.expect(&token::Colon)); + if try!(self.eat_keyword(keywords::While) ){ return self.parse_while_expr(Some(lifetime)) } - if self.eat_keyword(keywords::For) { + if try!(self.eat_keyword(keywords::For) ){ return self.parse_for_expr(Some(lifetime)) } - if self.eat_keyword(keywords::Loop) { + if try!(self.eat_keyword(keywords::Loop) ){ return self.parse_loop_expr(Some(lifetime)) } - self.fatal("expected `while`, `for`, or `loop` after a label") + return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } - if self.eat_keyword(keywords::Loop) { + if try!(self.eat_keyword(keywords::Loop) ){ return self.parse_loop_expr(None); } - if self.eat_keyword(keywords::Continue) { + if try!(self.eat_keyword(keywords::Continue) ){ let lo = self.span.lo; let ex = if self.token.is_lifetime() { let lifetime = self.get_lifetime(); - self.bump(); + try!(self.bump()); ExprAgain(Some(lifetime)) } else { ExprAgain(None) }; let hi = self.span.hi; - return self.mk_expr(lo, hi, ex); + return Ok(self.mk_expr(lo, hi, ex)); } - if self.eat_keyword(keywords::Match) { + if try!(self.eat_keyword(keywords::Match) ){ return self.parse_match_expr(); } - if self.eat_keyword(keywords::Unsafe) { + if try!(self.eat_keyword(keywords::Unsafe) ){ return self.parse_block_expr( lo, UnsafeBlock(ast::UserProvided)); } - if self.eat_keyword(keywords::Return) { + if try!(self.eat_keyword(keywords::Return) ){ // RETURN expression if self.token.can_begin_expr() { - let e = self.parse_expr(); + let e = try!(self.parse_expr_nopanic()); hi = e.span.hi; ex = ExprRet(Some(e)); } else { ex = ExprRet(None); } - } else if self.eat_keyword(keywords::Break) { + } else if try!(self.eat_keyword(keywords::Break) ){ // BREAK expression if self.token.is_lifetime() { let lifetime = self.get_lifetime(); - self.bump(); + try!(self.bump()); ex = ExprBreak(Some(lifetime)); } else { ex = ExprBreak(None); @@ -2108,48 +2150,48 @@ impl<'a> Parser<'a> { !self.check_keyword(keywords::True) && !self.check_keyword(keywords::False) { let pth = - self.parse_path(LifetimeAndTypesWithColons); + try!(self.parse_path(LifetimeAndTypesWithColons)); // `!`, as an operator, is prefix, so we know this isn't that if self.check(&token::Not) { // MACRO INVOCATION expression - self.bump(); + try!(self.bump()); - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end( + let delim = try!(self.expect_open_delim()); + let tts = try!(self.parse_seq_to_end( &token::CloseDelim(delim), seq_sep_none(), - |p| p.parse_token_tree()); - let hi = self.span.hi; + |p| p.parse_token_tree())); + let hi = self.last_span.hi; - return self.mk_mac_expr(lo, - hi, - MacInvocTT(pth, - tts, - EMPTY_CTXT)); + return Ok(self.mk_mac_expr(lo, + hi, + MacInvocTT(pth, + tts, + EMPTY_CTXT))); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited // from parsing struct literals here. if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) { // It's a struct literal. - self.bump(); + try!(self.bump()); let mut fields = Vec::new(); let mut base = None; while self.token != token::CloseDelim(token::Brace) { - if self.eat(&token::DotDot) { - base = Some(self.parse_expr()); + if try!(self.eat(&token::DotDot) ){ + base = Some(try!(self.parse_expr_nopanic())); break; } - fields.push(self.parse_field()); - self.commit_expr(&*fields.last().unwrap().expr, + fields.push(try!(self.parse_field())); + try!(self.commit_expr(&*fields.last().unwrap().expr, &[token::Comma], - &[token::CloseDelim(token::Brace)]); + &[token::CloseDelim(token::Brace)])); } - if fields.len() == 0 && base.is_none() { + if fields.is_empty() && base.is_none() { let last_span = self.last_span; self.span_err(last_span, "structure literal must either \ @@ -2159,9 +2201,9 @@ impl<'a> Parser<'a> { } hi = self.span.hi; - self.expect(&token::CloseDelim(token::Brace)); + try!(self.expect(&token::CloseDelim(token::Brace))); ex = ExprStruct(pth, fields, base); - return self.mk_expr(lo, hi, ex); + return Ok(self.mk_expr(lo, hi, ex)); } } @@ -2169,50 +2211,50 @@ impl<'a> Parser<'a> { ex = ExprPath(None, pth); } else { // other literal expression - let lit = self.parse_lit(); + let lit = try!(self.parse_lit()); hi = lit.span.hi; ex = ExprLit(P(lit)); } } } - return self.mk_expr(lo, hi, ex); + return Ok(self.mk_expr(lo, hi, ex)); } /// Parse a block or unsafe block pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode) - -> P { - self.expect(&token::OpenDelim(token::Brace)); - let blk = self.parse_block_tail(lo, blk_mode); - return self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); + -> PResult> { + try!(self.expect(&token::OpenDelim(token::Brace))); + let blk = try!(self.parse_block_tail(lo, blk_mode)); + return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))); } /// parse a.b or a(13) or a[4] or just a - pub fn parse_dot_or_call_expr(&mut self) -> P { - let b = self.parse_bottom_expr(); + pub fn parse_dot_or_call_expr(&mut self) -> PResult> { + let b = try!(self.parse_bottom_expr()); self.parse_dot_or_call_expr_with(b) } - pub fn parse_dot_or_call_expr_with(&mut self, e0: P) -> P { + pub fn parse_dot_or_call_expr_with(&mut self, e0: P) -> PResult> { let mut e = e0; let lo = e.span.lo; let mut hi; loop { // expr.f - if self.eat(&token::Dot) { + if try!(self.eat(&token::Dot) ){ match self.token { token::Ident(i, _) => { let dot = self.last_span.hi; hi = self.span.hi; - self.bump(); - let (_, tys, bindings) = if self.eat(&token::ModSep) { - self.expect_lt(); - self.parse_generic_values_after_lt() + try!(self.bump()); + let (_, tys, bindings) = if try!(self.eat(&token::ModSep) ){ + try!(self.expect_lt()); + try!(self.parse_generic_values_after_lt()) } else { (Vec::new(), Vec::new(), Vec::new()) }; - if bindings.len() > 0 { + if !bindings.is_empty() { let last_span = self.last_span; self.span_err(last_span, "type bindings are only permitted on trait paths"); } @@ -2220,12 +2262,12 @@ impl<'a> Parser<'a> { // expr.f() method call match self.token { token::OpenDelim(token::Paren) => { - let mut es = self.parse_unspanned_seq( + let mut es = try!(self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_expr() - ); + |p| Ok(try!(p.parse_expr_nopanic())) + )); hi = self.last_span.hi; es.insert(0, e); @@ -2255,7 +2297,7 @@ impl<'a> Parser<'a> { let dot = self.last_span.hi; hi = self.span.hi; - self.bump(); + try!(self.bump()); let index = n.as_str().parse::().ok(); match index { @@ -2271,7 +2313,7 @@ impl<'a> Parser<'a> { } } token::Literal(token::Float(n), _suf) => { - self.bump(); + try!(self.bump()); let last_span = self.last_span; let fstr = n.as_str(); self.span_err(last_span, @@ -2289,7 +2331,7 @@ impl<'a> Parser<'a> { self.abort_if_errors(); } - _ => self.unexpected() + _ => return Err(self.unexpected()) } continue; } @@ -2297,12 +2339,12 @@ impl<'a> Parser<'a> { match self.token { // expr(...) token::OpenDelim(token::Paren) => { - let es = self.parse_unspanned_seq( + let es = try!(self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_expr() - ); + |p| Ok(try!(p.parse_expr_nopanic())) + )); hi = self.last_span.hi; let nd = self.mk_call(e, es); @@ -2312,55 +2354,54 @@ impl<'a> Parser<'a> { // expr[...] // Could be either an index expression or a slicing expression. token::OpenDelim(token::Bracket) => { - self.bump(); - - let ix = self.parse_expr(); + try!(self.bump()); + let ix = try!(self.parse_expr_nopanic()); hi = self.span.hi; - self.commit_expr_expecting(&*ix, token::CloseDelim(token::Bracket)); + try!(self.commit_expr_expecting(&*ix, token::CloseDelim(token::Bracket))); let index = self.mk_index(e, ix); e = self.mk_expr(lo, hi, index) } - _ => return e + _ => return Ok(e) } } - return e; + return Ok(e); } // Parse unquoted tokens after a `$` in a token tree - fn parse_unquoted(&mut self) -> TokenTree { + fn parse_unquoted(&mut self) -> PResult { let mut sp = self.span; let (name, namep) = match self.token { token::Dollar => { - self.bump(); + try!(self.bump()); if self.token == token::OpenDelim(token::Paren) { - let Spanned { node: seq, span: seq_span } = self.parse_seq( + let Spanned { node: seq, span: seq_span } = try!(self.parse_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_none(), |p| p.parse_token_tree() - ); - let (sep, repeat) = self.parse_sep_and_kleene_op(); + )); + let (sep, repeat) = try!(self.parse_sep_and_kleene_op()); let name_num = macro_parser::count_names(&seq); - return TtSequence(mk_sp(sp.lo, seq_span.hi), + return Ok(TtSequence(mk_sp(sp.lo, seq_span.hi), Rc::new(SequenceRepetition { tts: seq, separator: sep, op: repeat, num_captures: name_num - })); + }))); } else if self.token.is_keyword_allow_following_colon(keywords::Crate) { - self.bump(); - return TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar)); + try!(self.bump()); + return Ok(TtToken(sp, SpecialVarNt(SpecialMacroVar::CrateMacroVar))); } else { sp = mk_sp(sp.lo, self.span.hi); let namep = match self.token { token::Ident(_, p) => p, _ => token::Plain }; - let name = self.parse_ident(); + let name = try!(self.parse_ident()); (name, namep) } } token::SubstNt(name, namep) => { - self.bump(); + try!(self.bump()); (name, namep) } _ => unreachable!() @@ -2369,58 +2410,59 @@ impl<'a> Parser<'a> { if self.token == token::Colon && self.look_ahead(1, |t| t.is_ident() && !t.is_strict_keyword() && !t.is_reserved_keyword()) { - self.bump(); + try!(self.bump()); sp = mk_sp(sp.lo, self.span.hi); let kindp = match self.token { token::Ident(_, p) => p, _ => token::Plain }; - let nt_kind = self.parse_ident(); - TtToken(sp, MatchNt(name, nt_kind, namep, kindp)) + let nt_kind = try!(self.parse_ident()); + Ok(TtToken(sp, MatchNt(name, nt_kind, namep, kindp))) } else { - TtToken(sp, SubstNt(name, namep)) + Ok(TtToken(sp, SubstNt(name, namep))) } } - pub fn check_unknown_macro_variable(&mut self) { + pub fn check_unknown_macro_variable(&mut self) -> PResult<()> { if self.quote_depth == 0 { match self.token { token::SubstNt(name, _) => - self.fatal(&format!("unknown macro variable `{}`", - token::get_ident(name))), + return Err(self.fatal(&format!("unknown macro variable `{}`", + token::get_ident(name)))), _ => {} } } + Ok(()) } /// Parse an optional separator followed by a Kleene-style /// repetition token (+ or *). - pub fn parse_sep_and_kleene_op(&mut self) -> (Option, ast::KleeneOp) { - fn parse_kleene_op(parser: &mut Parser) -> Option { + pub fn parse_sep_and_kleene_op(&mut self) -> PResult<(Option, ast::KleeneOp)> { + fn parse_kleene_op(parser: &mut Parser) -> PResult> { match parser.token { token::BinOp(token::Star) => { - parser.bump(); - Some(ast::ZeroOrMore) + try!(parser.bump()); + Ok(Some(ast::ZeroOrMore)) }, token::BinOp(token::Plus) => { - parser.bump(); - Some(ast::OneOrMore) + try!(parser.bump()); + Ok(Some(ast::OneOrMore)) }, - _ => None + _ => Ok(None) } }; - match parse_kleene_op(self) { - Some(kleene_op) => return (None, kleene_op), + match try!(parse_kleene_op(self)) { + Some(kleene_op) => return Ok((None, kleene_op)), None => {} } - let separator = self.bump_and_get(); - match parse_kleene_op(self) { - Some(zerok) => (Some(separator), zerok), - None => self.fatal("expected `*` or `+`") + let separator = try!(self.bump_and_get()); + match try!(parse_kleene_op(self)) { + Some(zerok) => Ok((Some(separator), zerok)), + None => return Err(self.fatal("expected `*` or `+`")) } } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> TokenTree { + pub fn parse_token_tree(&mut self) -> PResult { // FIXME #6994: currently, this is too eager. It // parses token trees but also identifies TtSequence's // and token::SubstNt's; it's too early to know yet @@ -2433,7 +2475,7 @@ impl<'a> Parser<'a> { // not an EOF, and not the desired right-delimiter (if // it were, parse_seq_to_before_end would have prevented // reaching this point. - fn parse_non_delim_tt_tok(p: &mut Parser) -> TokenTree { + fn parse_non_delim_tt_tok(p: &mut Parser) -> PResult { maybe_whole!(deref p, NtTT); match p.token { token::CloseDelim(_) => { @@ -2445,15 +2487,15 @@ impl<'a> Parser<'a> { Some(&sp) => p.span_note(sp, "unclosed delimiter"), }; let token_str = p.this_token_to_string(); - p.fatal(&format!("incorrect close delimiter: `{}`", - token_str)) + Err(p.fatal(&format!("incorrect close delimiter: `{}`", + token_str))) }, /* we ought to allow different depths of unquotation */ token::Dollar | token::SubstNt(..) if p.quote_depth > 0 => { p.parse_unquoted() } _ => { - TtToken(p.span, p.bump_and_get()) + Ok(TtToken(p.span, try!(p.bump_and_get()))) } } } @@ -2466,7 +2508,7 @@ impl<'a> Parser<'a> { } // There shouldn't really be a span, but it's easier for the test runner // if we give it one - self.fatal("this file contains an un-closed delimiter "); + return Err(self.fatal("this file contains an un-closed delimiter ")); }, token::OpenDelim(delim) => { // The span for beginning of the delimited section @@ -2475,29 +2517,29 @@ impl<'a> Parser<'a> { // Parse the open delimiter. self.open_braces.push(self.span); let open_span = self.span; - self.bump(); + try!(self.bump()); // Parse the token trees within the delimiters - let tts = self.parse_seq_to_before_end( + let tts = try!(self.parse_seq_to_before_end( &token::CloseDelim(delim), seq_sep_none(), |p| p.parse_token_tree() - ); + )); // Parse the close delimiter. let close_span = self.span; - self.bump(); + try!(self.bump()); self.open_braces.pop().unwrap(); // Expand to cover the entire delimited token tree let span = Span { hi: close_span.hi, ..pre_span }; - TtDelimited(span, Rc::new(Delimited { + Ok(TtDelimited(span, Rc::new(Delimited { delim: delim, open_span: open_span, tts: tts, close_span: close_span, - })) + }))) }, _ => parse_non_delim_tt_tok(self), } @@ -2505,16 +2547,16 @@ impl<'a> Parser<'a> { // parse a stream of tokens into a list of TokenTree's, // up to EOF. - pub fn parse_all_token_trees(&mut self) -> Vec { + pub fn parse_all_token_trees(&mut self) -> PResult> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()); + tts.push(try!(self.parse_token_tree())); } - tts + Ok(tts) } /// Parse a prefix-operator expr - pub fn parse_prefix_expr(&mut self) -> P { + pub fn parse_prefix_expr(&mut self) -> PResult> { let lo = self.span.lo; let hi; @@ -2522,27 +2564,27 @@ impl<'a> Parser<'a> { let ex; match self.token { token::Not => { - self.bump(); - let e = self.parse_prefix_expr(); + try!(self.bump()); + let e = try!(self.parse_prefix_expr()); hi = e.span.hi; ex = self.mk_unary(UnNot, e); } token::BinOp(token::Minus) => { - self.bump(); - let e = self.parse_prefix_expr(); + try!(self.bump()); + let e = try!(self.parse_prefix_expr()); hi = e.span.hi; ex = self.mk_unary(UnNeg, e); } token::BinOp(token::Star) => { - self.bump(); - let e = self.parse_prefix_expr(); + try!(self.bump()); + let e = try!(self.parse_prefix_expr()); hi = e.span.hi; ex = self.mk_unary(UnDeref, e); } token::BinOp(token::And) | token::AndAnd => { - self.expect_and(); - let m = self.parse_mutability(); - let e = self.parse_prefix_expr(); + try!(self.expect_and()); + let m = try!(self.parse_mutability()); + let e = try!(self.parse_prefix_expr()); hi = e.span.hi; ex = ExprAddrOf(m, e); } @@ -2553,14 +2595,14 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - self.bump(); + try!(self.bump()); // Check for a place: `box(PLACE) EXPR`. - if self.eat(&token::OpenDelim(token::Paren)) { + if try!(self.eat(&token::OpenDelim(token::Paren)) ){ // Support `box() EXPR` as the default. - if !self.eat(&token::CloseDelim(token::Paren)) { - let place = self.parse_expr(); - self.expect(&token::CloseDelim(token::Paren)); + if !try!(self.eat(&token::CloseDelim(token::Paren)) ){ + let place = try!(self.parse_expr_nopanic()); + try!(self.expect(&token::CloseDelim(token::Paren))); // Give a suggestion to use `box()` when a parenthesised expression is used if !self.token.can_begin_expr() { let span = self.span; @@ -2573,15 +2615,15 @@ impl<'a> Parser<'a> { "perhaps you meant `box() (foo)` instead?"); self.abort_if_errors(); } - let subexpression = self.parse_prefix_expr(); + let subexpression = try!(self.parse_prefix_expr()); hi = subexpression.span.hi; ex = ExprBox(Some(place), subexpression); - return self.mk_expr(lo, hi, ex); + return Ok(self.mk_expr(lo, hi, ex)); } } // Otherwise, we use the unique pointer default. - let subexpression = self.parse_prefix_expr(); + let subexpression = try!(self.parse_prefix_expr()); hi = subexpression.span.hi; // FIXME (pnkfelix): After working out kinks with box // desugaring, should be `ExprBox(None, subexpression)` @@ -2590,25 +2632,18 @@ impl<'a> Parser<'a> { } _ => return self.parse_dot_or_call_expr() } - return self.mk_expr(lo, hi, ex); + return Ok(self.mk_expr(lo, hi, ex)); } /// Parse an expression of binops - pub fn parse_binops(&mut self) -> P { - let prefix_expr = self.parse_prefix_expr(); + pub fn parse_binops(&mut self) -> PResult> { + let prefix_expr = try!(self.parse_prefix_expr()); self.parse_more_binops(prefix_expr, 0) } /// Parse an expression of binops of at least min_prec precedence - pub fn parse_more_binops(&mut self, lhs: P, min_prec: usize) -> P { - if self.expr_is_complete(&*lhs) { return lhs; } - - // Prevent dynamic borrow errors later on by limiting the - // scope of the borrows. - if self.token == token::BinOp(token::Or) && - self.restrictions.contains(RESTRICTION_NO_BAR_OP) { - return lhs; - } + pub fn parse_more_binops(&mut self, lhs: P, min_prec: usize) -> PResult> { + if self.expr_is_complete(&*lhs) { return Ok(lhs); } self.expected_tokens.push(TokenType::Operator); @@ -2621,27 +2656,27 @@ impl<'a> Parser<'a> { } let cur_prec = operator_prec(cur_op); if cur_prec >= min_prec { - self.bump(); - let expr = self.parse_prefix_expr(); - let rhs = self.parse_more_binops(expr, cur_prec + 1); + try!(self.bump()); + let expr = try!(self.parse_prefix_expr()); + let rhs = try!(self.parse_more_binops(expr, cur_prec + 1)); let lhs_span = lhs.span; let rhs_span = rhs.span; let binary = self.mk_binary(codemap::respan(cur_op_span, cur_op), lhs, rhs); let bin = self.mk_expr(lhs_span.lo, rhs_span.hi, binary); self.parse_more_binops(bin, min_prec) } else { - lhs + Ok(lhs) } } None => { - if AS_PREC >= min_prec && self.eat_keyword_noexpect(keywords::As) { - let rhs = self.parse_ty(); + if AS_PREC >= min_prec && try!(self.eat_keyword_noexpect(keywords::As) ){ + let rhs = try!(self.parse_ty_nopanic()); let _as = self.mk_expr(lhs.span.lo, rhs.span.hi, ExprCast(lhs, rhs)); self.parse_more_binops(_as, min_prec) } else { - lhs + Ok(lhs) } } } @@ -2670,7 +2705,7 @@ impl<'a> Parser<'a> { /// Parse an assignment expression.... /// actually, this seems to be the main entry point for /// parsing an arbitrary expression. - pub fn parse_assign_expr(&mut self) -> P { + pub fn parse_assign_expr(&mut self) -> PResult> { match self.token { token::DotDot => { // prefix-form of range notation '..expr' @@ -2678,36 +2713,36 @@ impl<'a> Parser<'a> { // (much lower than other prefix expressions) to be consistent // with the postfix-form 'expr..' let lo = self.span.lo; - self.bump(); + try!(self.bump()); let opt_end = if self.is_at_start_of_range_notation_rhs() { - let end = self.parse_binops(); + let end = try!(self.parse_binops()); Some(end) } else { None }; let hi = self.span.hi; let ex = self.mk_range(None, opt_end); - self.mk_expr(lo, hi, ex) + Ok(self.mk_expr(lo, hi, ex)) } _ => { - let lhs = self.parse_binops(); + let lhs = try!(self.parse_binops()); self.parse_assign_expr_with(lhs) } } } - pub fn parse_assign_expr_with(&mut self, lhs: P) -> P { + pub fn parse_assign_expr_with(&mut self, lhs: P) -> PResult> { let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; let op_span = self.span; match self.token { token::Eq => { - self.bump(); - let rhs = self.parse_expr_res(restrictions); - self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs)) + try!(self.bump()); + let rhs = try!(self.parse_expr_res(restrictions)); + Ok(self.mk_expr(lhs.span.lo, rhs.span.hi, ExprAssign(lhs, rhs))) } token::BinOpEq(op) => { - self.bump(); - let rhs = self.parse_expr_res(restrictions); + try!(self.bump()); + let rhs = try!(self.parse_expr_res(restrictions)); let aop = match op { token::Plus => BiAdd, token::Minus => BiSub, @@ -2723,14 +2758,14 @@ impl<'a> Parser<'a> { let rhs_span = rhs.span; let span = lhs.span; let assign_op = self.mk_assign_op(codemap::respan(op_span, aop), lhs, rhs); - self.mk_expr(span.lo, rhs_span.hi, assign_op) + Ok(self.mk_expr(span.lo, rhs_span.hi, assign_op)) } // A range expression, either `expr..expr` or `expr..`. token::DotDot => { - self.bump(); + try!(self.bump()); let opt_end = if self.is_at_start_of_range_notation_rhs() { - let end = self.parse_binops(); + let end = try!(self.parse_binops()); Some(end) } else { None @@ -2739,11 +2774,11 @@ impl<'a> Parser<'a> { let lo = lhs.span.lo; let hi = self.span.hi; let range = self.mk_range(Some(lhs), opt_end); - return self.mk_expr(lo, hi, range); + return Ok(self.mk_expr(lo, hi, range)); } _ => { - lhs + Ok(lhs) } } } @@ -2761,51 +2796,51 @@ impl<'a> Parser<'a> { } /// Parse an 'if' or 'if let' expression ('if' token already eaten) - pub fn parse_if_expr(&mut self) -> P { + pub fn parse_if_expr(&mut self) -> PResult> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(); } let lo = self.last_span.lo; - let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - let thn = self.parse_block(); + let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let thn = try!(self.parse_block()); let mut els: Option> = None; let mut hi = thn.span.hi; - if self.eat_keyword(keywords::Else) { - let elexpr = self.parse_else_expr(); + if try!(self.eat_keyword(keywords::Else) ){ + let elexpr = try!(self.parse_else_expr()); hi = elexpr.span.hi; els = Some(elexpr); } - self.mk_expr(lo, hi, ExprIf(cond, thn, els)) + Ok(self.mk_expr(lo, hi, ExprIf(cond, thn, els))) } /// Parse an 'if let' expression ('if' token already eaten) - pub fn parse_if_let_expr(&mut self) -> P { + pub fn parse_if_let_expr(&mut self) -> PResult> { let lo = self.last_span.lo; - self.expect_keyword(keywords::Let); - let pat = self.parse_pat(); - self.expect(&token::Eq); - let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - let thn = self.parse_block(); - let (hi, els) = if self.eat_keyword(keywords::Else) { - let expr = self.parse_else_expr(); + try!(self.expect_keyword(keywords::Let)); + let pat = try!(self.parse_pat_nopanic()); + try!(self.expect(&token::Eq)); + let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let thn = try!(self.parse_block()); + let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){ + let expr = try!(self.parse_else_expr()); (expr.span.hi, Some(expr)) } else { (thn.span.hi, None) }; - self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els)) + Ok(self.mk_expr(lo, hi, ExprIfLet(pat, expr, thn, els))) } // `|args| expr` pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause) - -> P + -> PResult> { let lo = self.span.lo; - let decl = self.parse_fn_block_decl(); + let decl = try!(self.parse_fn_block_decl()); let body = match decl.output { DefaultReturn(_) => { // If no explicit return type is given, parse any // expr and wrap it up in a dummy block: - let body_expr = self.parse_expr(); + let body_expr = try!(self.parse_expr_nopanic()); P(ast::Block { id: ast::DUMMY_NODE_ID, stmts: vec![], @@ -2817,148 +2852,165 @@ impl<'a> Parser<'a> { _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - self.parse_block() + try!(self.parse_block()) } }; - self.mk_expr( + Ok(self.mk_expr( lo, body.span.hi, - ExprClosure(capture_clause, decl, body)) + ExprClosure(capture_clause, decl, body))) } - pub fn parse_else_expr(&mut self) -> P { - if self.eat_keyword(keywords::If) { + pub fn parse_else_expr(&mut self) -> PResult> { + if try!(self.eat_keyword(keywords::If) ){ return self.parse_if_expr(); } else { - let blk = self.parse_block(); - return self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk)); + let blk = try!(self.parse_block()); + return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) - pub fn parse_for_expr(&mut self, opt_ident: Option) -> P { + pub fn parse_for_expr(&mut self, opt_ident: Option) -> PResult> { // Parse: `for in ` let lo = self.last_span.lo; - let pat = self.parse_pat(); - self.expect_keyword(keywords::In); - let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - let loop_block = self.parse_block(); - let hi = self.span.hi; + let pat = try!(self.parse_pat_nopanic()); + try!(self.expect_keyword(keywords::In)); + let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let loop_block = try!(self.parse_block()); + let hi = self.last_span.hi; - self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident)) + Ok(self.mk_expr(lo, hi, ExprForLoop(pat, expr, loop_block, opt_ident))) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) - pub fn parse_while_expr(&mut self, opt_ident: Option) -> P { + pub fn parse_while_expr(&mut self, opt_ident: Option) -> PResult> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident); } let lo = self.last_span.lo; - let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - let body = self.parse_block(); + let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let body = try!(self.parse_block()); let hi = body.span.hi; - return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)); + return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident))); } /// Parse a 'while let' expression ('while' token already eaten) - pub fn parse_while_let_expr(&mut self, opt_ident: Option) -> P { + pub fn parse_while_let_expr(&mut self, opt_ident: Option) -> PResult> { let lo = self.last_span.lo; - self.expect_keyword(keywords::Let); - let pat = self.parse_pat(); - self.expect(&token::Eq); - let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - let body = self.parse_block(); + try!(self.expect_keyword(keywords::Let)); + let pat = try!(self.parse_pat_nopanic()); + try!(self.expect(&token::Eq)); + let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let body = try!(self.parse_block()); let hi = body.span.hi; - return self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident)); + return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident))); } - pub fn parse_loop_expr(&mut self, opt_ident: Option) -> P { + pub fn parse_loop_expr(&mut self, opt_ident: Option) -> PResult> { let lo = self.last_span.lo; - let body = self.parse_block(); + let body = try!(self.parse_block()); let hi = body.span.hi; - self.mk_expr(lo, hi, ExprLoop(body, opt_ident)) + Ok(self.mk_expr(lo, hi, ExprLoop(body, opt_ident))) } - fn parse_match_expr(&mut self) -> P { + fn parse_match_expr(&mut self) -> PResult> { let lo = self.last_span.lo; - let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); - self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)); + let discriminant = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace))); let mut arms: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { - arms.push(self.parse_arm()); + arms.push(try!(self.parse_arm_nopanic())); } let hi = self.span.hi; - self.bump(); - return self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal)); + try!(self.bump()); + return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal))); } - pub fn parse_arm(&mut self) -> Arm { + pub fn parse_arm_nopanic(&mut self) -> PResult { let attrs = self.parse_outer_attributes(); - let pats = self.parse_pats(); + let pats = try!(self.parse_pats()); let mut guard = None; - if self.eat_keyword(keywords::If) { - guard = Some(self.parse_expr()); + if try!(self.eat_keyword(keywords::If) ){ + guard = Some(try!(self.parse_expr_nopanic())); } - self.expect(&token::FatArrow); - let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR); + try!(self.expect(&token::FatArrow)); + let expr = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); let require_comma = !classify::expr_is_simple_block(&*expr) && self.token != token::CloseDelim(token::Brace); if require_comma { - self.commit_expr(&*expr, &[token::Comma], &[token::CloseDelim(token::Brace)]); + try!(self.commit_expr(&*expr, &[token::Comma], &[token::CloseDelim(token::Brace)])); } else { - self.eat(&token::Comma); + try!(self.eat(&token::Comma)); } - ast::Arm { + Ok(ast::Arm { attrs: attrs, pats: pats, guard: guard, body: expr, - } + }) } /// Parse an expression - pub fn parse_expr(&mut self) -> P { + pub fn parse_expr_nopanic(&mut self) -> PResult> { return self.parse_expr_res(UNRESTRICTED); } /// Parse an expression, subject to the given restrictions - pub fn parse_expr_res(&mut self, r: Restrictions) -> P { + pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult> { let old = self.restrictions; self.restrictions = r; - let e = self.parse_assign_expr(); + let e = try!(self.parse_assign_expr()); self.restrictions = old; - return e; + return Ok(e); } /// Parse the RHS of a local variable declaration (e.g. '= 14;') - fn parse_initializer(&mut self) -> Option> { + fn parse_initializer(&mut self) -> PResult>> { if self.check(&token::Eq) { - self.bump(); - Some(self.parse_expr()) + try!(self.bump()); + Ok(Some(try!(self.parse_expr_nopanic()))) } else { - None + Ok(None) } } /// Parse patterns, separated by '|' s - fn parse_pats(&mut self) -> Vec> { + fn parse_pats(&mut self) -> PResult>> { let mut pats = Vec::new(); loop { - pats.push(self.parse_pat()); - if self.check(&token::BinOp(token::Or)) { self.bump(); } - else { return pats; } + pats.push(try!(self.parse_pat_nopanic())); + if self.check(&token::BinOp(token::Or)) { try!(self.bump());} + else { return Ok(pats); } }; } + fn parse_pat_tuple_elements(&mut self) -> PResult>> { + let mut fields = vec![]; + if !self.check(&token::CloseDelim(token::Paren)) { + fields.push(try!(self.parse_pat_nopanic())); + if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { + while try!(self.eat(&token::Comma)) && + !self.check(&token::CloseDelim(token::Paren)) { + fields.push(try!(self.parse_pat_nopanic())); + } + } + if fields.len() == 1 { + try!(self.expect(&token::Comma)); + } + } + Ok(fields) + } + fn parse_pat_vec_elements( &mut self, - ) -> (Vec>, Option>, Vec>) { + ) -> PResult<(Vec>, Option>, Vec>)> { let mut before = Vec::new(); let mut slice = None; let mut after = Vec::new(); @@ -2969,17 +3021,17 @@ impl<'a> Parser<'a> { if first { first = false; } else { - self.expect(&token::Comma); + try!(self.expect(&token::Comma)); if self.token == token::CloseDelim(token::Bracket) - && (before_slice || after.len() != 0) { + && (before_slice || !after.is_empty()) { break } } if before_slice { if self.check(&token::DotDot) { - self.bump(); + try!(self.bump()); if self.check(&token::Comma) || self.check(&token::CloseDelim(token::Bracket)) { @@ -2994,9 +3046,9 @@ impl<'a> Parser<'a> { } } - let subpat = self.parse_pat(); + let subpat = try!(self.parse_pat_nopanic()); if before_slice && self.check(&token::DotDot) { - self.bump(); + try!(self.bump()); slice = Some(subpat); before_slice = false; } else if before_slice { @@ -3006,11 +3058,11 @@ impl<'a> Parser<'a> { } } - (before, slice, after) + Ok((before, slice, after)) } /// Parse the fields of a struct-like pattern - fn parse_pat_fields(&mut self) -> (Vec> , bool) { + fn parse_pat_fields(&mut self) -> PResult<(Vec> , bool)> { let mut fields = Vec::new(); let mut etc = false; let mut first = true; @@ -3018,7 +3070,7 @@ impl<'a> Parser<'a> { if first { first = false; } else { - self.expect(&token::Comma); + try!(self.expect(&token::Comma)); // accept trailing commas if self.check(&token::CloseDelim(token::Brace)) { break } } @@ -3027,11 +3079,11 @@ impl<'a> Parser<'a> { let hi; if self.check(&token::DotDot) { - self.bump(); + try!(self.bump()); if self.token != token::CloseDelim(token::Brace) { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `{}`, found `{}`", "}", - token_str)) + return Err(self.fatal(&format!("expected `{}`, found `{}`", "}", + token_str))) } etc = true; break; @@ -3040,18 +3092,18 @@ impl<'a> Parser<'a> { // Check if a colon exists one ahead. This means we're parsing a fieldname. let (subpat, fieldname, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { // Parsing a pattern of the form "fieldname: pat" - let fieldname = self.parse_ident(); - self.bump(); - let pat = self.parse_pat(); + let fieldname = try!(self.parse_ident()); + try!(self.bump()); + let pat = try!(self.parse_pat_nopanic()); hi = pat.span.hi; (pat, fieldname, false) } else { // Parsing a pattern of the form "(box) (ref) (mut) fieldname" - let is_box = self.eat_keyword(keywords::Box); + let is_box = try!(self.eat_keyword(keywords::Box)); let boxed_span_lo = self.span.lo; - let is_ref = self.eat_keyword(keywords::Ref); - let is_mut = self.eat_keyword(keywords::Mut); - let fieldname = self.parse_ident(); + let is_ref = try!(self.eat_keyword(keywords::Ref)); + let is_mut = try!(self.eat_keyword(keywords::Mut)); + let fieldname = try!(self.parse_ident()); hi = self.last_span.hi; let bind_type = match (is_ref, is_mut) { @@ -3084,258 +3136,157 @@ impl<'a> Parser<'a> { pat: subpat, is_shorthand: is_shorthand }}); } - return (fields, etc); + return Ok((fields, etc)); + } + + fn parse_pat_range_end(&mut self) -> PResult> { + if self.is_path_start() { + let lo = self.span.lo; + let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + let hi = self.last_span.hi; + Ok(self.mk_expr(lo, hi, ExprPath(None, path))) + } else { + self.parse_literal_maybe_minus() + } + } + + fn is_path_start(&self) -> bool { + (self.token == token::ModSep || self.token.is_ident() || self.token.is_path()) + && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False) } /// Parse a pattern. - pub fn parse_pat(&mut self) -> P { + pub fn parse_pat_nopanic(&mut self) -> PResult> { maybe_whole!(self, NtPat); let lo = self.span.lo; - let mut hi; let pat; match self.token { - // parse _ token::Underscore => { - self.bump(); + // Parse _ + try!(self.bump()); pat = PatWild(PatWildSingle); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) } token::BinOp(token::And) | token::AndAnd => { - // parse &pat and &mut pat - let lo = self.span.lo; - self.expect_and(); - let mutability = if self.eat_keyword(keywords::Mut) { - ast::MutMutable - } else { - ast::MutImmutable - }; - let sub = self.parse_pat(); - pat = PatRegion(sub, mutability); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + // Parse &pat / &mut pat + try!(self.expect_and()); + let mutbl = try!(self.parse_mutability()); + let subpat = try!(self.parse_pat_nopanic()); + pat = PatRegion(subpat, mutbl); } token::OpenDelim(token::Paren) => { - // parse (pat,pat,pat,...) as tuple - self.bump(); - if self.check(&token::CloseDelim(token::Paren)) { - self.bump(); - pat = PatTup(vec![]); - } else { - let mut fields = vec!(self.parse_pat()); - if self.look_ahead(1, |t| *t != token::CloseDelim(token::Paren)) { - while self.check(&token::Comma) { - self.bump(); - if self.check(&token::CloseDelim(token::Paren)) { break; } - fields.push(self.parse_pat()); - } - } - if fields.len() == 1 { self.expect(&token::Comma); } - self.expect(&token::CloseDelim(token::Paren)); - pat = PatTup(fields); - } - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + // Parse (pat,pat,pat,...) as tuple pattern + try!(self.bump()); + let fields = try!(self.parse_pat_tuple_elements()); + try!(self.expect(&token::CloseDelim(token::Paren))); + pat = PatTup(fields); } token::OpenDelim(token::Bracket) => { - // parse [pat,pat,...] as vector pattern - self.bump(); - let (before, slice, after) = - self.parse_pat_vec_elements(); - - self.expect(&token::CloseDelim(token::Bracket)); - pat = ast::PatVec(before, slice, after); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) + // Parse [pat,pat,...] as vector pattern + try!(self.bump()); + let (before, slice, after) = try!(self.parse_pat_vec_elements()); + try!(self.expect(&token::CloseDelim(token::Bracket))); + pat = PatVec(before, slice, after); } - _ => {} - } - // at this point, token != _, ~, &, &&, (, [ - - if (!(self.token.is_ident() || self.token.is_path()) - && self.token != token::ModSep) - || self.token.is_keyword(keywords::True) - || self.token.is_keyword(keywords::False) { - // Parse an expression pattern or exp ... exp. - // - // These expressions are limited to literals (possibly - // preceded by unary-minus) or identifiers. - let val = self.parse_literal_maybe_minus(); - if (self.check(&token::DotDotDot)) && - self.look_ahead(1, |t| { - *t != token::Comma && *t != token::CloseDelim(token::Bracket) - }) { - self.bump(); - let end = if self.token.is_ident() || self.token.is_path() { - let path = self.parse_path(LifetimeAndTypesWithColons); - let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(None, path)) - } else { - self.parse_literal_maybe_minus() - }; - pat = PatRange(val, end); - } else { - pat = PatLit(val); - } - } else if self.eat_keyword(keywords::Mut) { - pat = self.parse_pat_ident(BindByValue(MutMutable)); - } else if self.eat_keyword(keywords::Ref) { - // parse ref pat - let mutbl = self.parse_mutability(); - pat = self.parse_pat_ident(BindByRef(mutbl)); - } else if self.eat_keyword(keywords::Box) { - // `box PAT` - // - // FIXME(#13910): Rename to `PatBox` and extend to full DST - // support. - let sub = self.parse_pat(); - pat = PatBox(sub); - hi = self.last_span.hi; - return P(ast::Pat { - id: ast::DUMMY_NODE_ID, - node: pat, - span: mk_sp(lo, hi) - }) - } else { - let can_be_enum_or_struct = self.look_ahead(1, |t| { - match *t { - token::OpenDelim(_) | token::Lt | token::ModSep => true, - _ => false, - } - }); - - if self.look_ahead(1, |t| *t == token::DotDotDot) && - self.look_ahead(2, |t| { - *t != token::Comma && *t != token::CloseDelim(token::Bracket) - }) { - let start = self.parse_expr_res(RESTRICTION_NO_BAR_OP); - self.eat(&token::DotDotDot); - let end = self.parse_expr_res(RESTRICTION_NO_BAR_OP); - pat = PatRange(start, end); - } else if self.token.is_plain_ident() && !can_be_enum_or_struct { - let id = self.parse_ident(); - let id_span = self.last_span; - let pth1 = codemap::Spanned{span:id_span, node: id}; - if self.eat(&token::Not) { - // macro invocation - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), - seq_sep_none(), - |p| p.parse_token_tree()); - - let mac = MacInvocTT(ident_to_path(id_span,id), tts, EMPTY_CTXT); - pat = ast::PatMac(codemap::Spanned {node: mac, span: self.span}); - } else { - let sub = if self.eat(&token::At) { - // parse foo @ pat - Some(self.parse_pat()) + _ => { + // At this point, token != _, &, &&, (, [ + if try!(self.eat_keyword(keywords::Mut)) { + // Parse mut ident @ pat + pat = try!(self.parse_pat_ident(BindByValue(MutMutable))); + } else if try!(self.eat_keyword(keywords::Ref)) { + // Parse ref ident @ pat / ref mut ident @ pat + let mutbl = try!(self.parse_mutability()); + pat = try!(self.parse_pat_ident(BindByRef(mutbl))); + } else if try!(self.eat_keyword(keywords::Box)) { + // Parse box pat + let subpat = try!(self.parse_pat_nopanic()); + pat = PatBox(subpat); + } else if self.is_path_start() { + // Parse pattern starting with a path + if self.token.is_plain_ident() && self.look_ahead(1, |t| *t != token::DotDotDot && + *t != token::OpenDelim(token::Brace) && + *t != token::OpenDelim(token::Paren) && + // Contrary to its definition, a plain ident can be followed by :: in macros + *t != token::ModSep) { + // Plain idents have some extra abilities here compared to general paths + if self.look_ahead(1, |t| *t == token::Not) { + // Parse macro invocation + let ident = try!(self.parse_ident()); + let ident_span = self.last_span; + let path = ident_to_path(ident_span, ident); + try!(self.bump()); + let delim = try!(self.expect_open_delim()); + let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim), + seq_sep_none(), |p| p.parse_token_tree())); + let mac = MacInvocTT(path, tts, EMPTY_CTXT); + pat = PatMac(codemap::Spanned {node: mac, span: self.span}); } else { - // or just foo - None - }; - pat = PatIdent(BindByValue(MutImmutable), pth1, sub); - } - } else if self.look_ahead(1, |t| *t == token::Lt) { - self.bump(); - self.unexpected() - } else { - // parse an enum pat - let enum_path = self.parse_path(LifetimeAndTypesWithColons); - match self.token { - token::OpenDelim(token::Brace) => { - self.bump(); - let (fields, etc) = - self.parse_pat_fields(); - self.bump(); - pat = PatStruct(enum_path, fields, etc); + // Parse ident @ pat + // This can give false positives and parse nullary enums, + // they are dealt with later in resolve + pat = try!(self.parse_pat_ident(BindByValue(MutImmutable))); } - token::DotDotDot => { + } else { + // Parse as a general path + let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + match self.token { + token::DotDotDot => { + // Parse range let hi = self.last_span.hi; - let start = self.mk_expr(lo, hi, ExprPath(None, enum_path)); - self.eat(&token::DotDotDot); - let end = if self.token.is_ident() || self.token.is_path() { - let path = self.parse_path(LifetimeAndTypesWithColons); - let hi = self.span.hi; - self.mk_expr(lo, hi, ExprPath(None, path)) + let begin = self.mk_expr(lo, hi, ExprPath(None, path)); + try!(self.bump()); + let end = try!(self.parse_pat_range_end()); + pat = PatRange(begin, end); + } + token::OpenDelim(token::Brace) => { + // Parse struct pattern + try!(self.bump()); + let (fields, etc) = try!(self.parse_pat_fields()); + try!(self.bump()); + pat = PatStruct(path, fields, etc); + } + token::OpenDelim(token::Paren) => { + // Parse tuple struct or enum pattern + if self.look_ahead(1, |t| *t == token::DotDot) { + // This is a "top constructor only" pat + try!(self.bump()); + try!(self.bump()); + try!(self.expect(&token::CloseDelim(token::Paren))); + pat = PatEnum(path, None); } else { - self.parse_literal_maybe_minus() - }; - pat = PatRange(start, end); - } - _ => { - let mut args: Vec> = Vec::new(); - match self.token { - token::OpenDelim(token::Paren) => { - let is_dotdot = self.look_ahead(1, |t| { - match *t { - token::DotDot => true, - _ => false, - } - }); - if is_dotdot { - // This is a "top constructor only" pat - self.bump(); - self.bump(); - self.expect(&token::CloseDelim(token::Paren)); - pat = PatEnum(enum_path, None); - } else { - args = self.parse_enum_variant_seq( + let args = try!(self.parse_enum_variant_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_pat() - ); - pat = PatEnum(enum_path, Some(args)); - } - }, - _ => { - if !enum_path.global && - enum_path.segments.len() == 1 && - enum_path.segments[0].parameters.is_empty() - { - // NB: If enum_path is a single identifier, - // this should not be reachable due to special - // handling further above. - // - // However, previously a PatIdent got emitted - // here, so we preserve the branch just in case. - // - // A rewrite of the logic in this function - // would probably make this obvious. - self.span_bug(enum_path.span, - "ident only path should have been covered already"); - } else { - pat = PatEnum(enum_path, Some(args)); - } - } + |p| p.parse_pat_nopanic())); + pat = PatEnum(path, Some(args)); } + } + _ => { + // Parse nullary enum + pat = PatEnum(path, Some(vec![])); + } } } + } else { + // Try to parse everything else as literal with optional minus + let begin = try!(self.parse_literal_maybe_minus()); + if try!(self.eat(&token::DotDotDot)) { + let end = try!(self.parse_pat_range_end()); + pat = PatRange(begin, end); + } else { + pat = PatLit(begin); + } } + } } - hi = self.last_span.hi; - P(ast::Pat { + + let hi = self.last_span.hi; + Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, span: mk_sp(lo, hi), - }) + })) } /// Parse ident or ident @ pat @@ -3343,18 +3294,18 @@ impl<'a> Parser<'a> { /// error message when parsing mistakes like ref foo(a,b) fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) - -> ast::Pat_ { + -> PResult { if !self.token.is_plain_ident() { let span = self.span; let tok_str = self.this_token_to_string(); - self.span_fatal(span, - &format!("expected identifier, found `{}`", tok_str)); + return Err(self.span_fatal(span, + &format!("expected identifier, found `{}`", tok_str))) } - let ident = self.parse_ident(); + let ident = try!(self.parse_ident()); let last_span = self.last_span; let name = codemap::Spanned{span: last_span, node: ident}; - let sub = if self.eat(&token::At) { - Some(self.parse_pat()) + let sub = if try!(self.eat(&token::At) ){ + Some(try!(self.parse_pat_nopanic())) } else { None }; @@ -3367,57 +3318,57 @@ impl<'a> Parser<'a> { // will direct us over to parse_enum_variant() if self.token == token::OpenDelim(token::Paren) { let last_span = self.last_span; - self.span_fatal( + return Err(self.span_fatal( last_span, - "expected identifier, found enum pattern"); + "expected identifier, found enum pattern")) } - PatIdent(binding_mode, name, sub) + Ok(PatIdent(binding_mode, name, sub)) } /// Parse a local variable declaration - fn parse_local(&mut self) -> P { + fn parse_local(&mut self) -> PResult> { let lo = self.span.lo; - let pat = self.parse_pat(); + let pat = try!(self.parse_pat_nopanic()); let mut ty = None; - if self.eat(&token::Colon) { - ty = Some(self.parse_ty_sum()); + if try!(self.eat(&token::Colon) ){ + ty = Some(try!(self.parse_ty_sum())); } - let init = self.parse_initializer(); - P(ast::Local { + let init = try!(self.parse_initializer()); + Ok(P(ast::Local { ty: ty, pat: pat, init: init, id: ast::DUMMY_NODE_ID, span: mk_sp(lo, self.last_span.hi), source: LocalLet, - }) + })) } /// Parse a "let" stmt - fn parse_let(&mut self) -> P { + fn parse_let(&mut self) -> PResult> { let lo = self.span.lo; - let local = self.parse_local(); - P(spanned(lo, self.last_span.hi, DeclLocal(local))) + let local = try!(self.parse_local()); + Ok(P(spanned(lo, self.last_span.hi, DeclLocal(local)))) } /// Parse a structure field fn parse_name_and_ty(&mut self, pr: Visibility, - attrs: Vec ) -> StructField { + attrs: Vec ) -> PResult { let lo = self.span.lo; if !self.token.is_plain_ident() { - self.fatal("expected ident"); + return Err(self.fatal("expected ident")); } - let name = self.parse_ident(); - self.expect(&token::Colon); - let ty = self.parse_ty_sum(); - spanned(lo, self.last_span.hi, ast::StructField_ { + let name = try!(self.parse_ident()); + try!(self.expect(&token::Colon)); + let ty = try!(self.parse_ty_sum()); + Ok(spanned(lo, self.last_span.hi, ast::StructField_ { kind: NamedField(name, pr), id: ast::DUMMY_NODE_ID, ty: ty, attrs: attrs, - }) + })) } /// Emit an expected item after attributes error. @@ -3433,11 +3384,11 @@ impl<'a> Parser<'a> { } /// Parse a statement. may include decl. - pub fn parse_stmt(&mut self) -> Option> { - self.parse_stmt_().map(P) + pub fn parse_stmt_nopanic(&mut self) -> PResult>> { + Ok(try!(self.parse_stmt_()).map(P)) } - fn parse_stmt_(&mut self) -> Option { + fn parse_stmt_(&mut self) -> PResult> { maybe_whole!(Some deref self, NtStmt); fn check_expected_item(p: &mut Parser, attrs: &[Attribute]) { @@ -3450,10 +3401,10 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let attrs = self.parse_outer_attributes(); - Some(if self.check_keyword(keywords::Let) { + Ok(Some(if self.check_keyword(keywords::Let) { check_expected_item(self, &attrs); - self.expect_keyword(keywords::Let); - let decl = self.parse_let(); + try!(self.expect_keyword(keywords::Let)); + let decl = try!(self.parse_let()); spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID)) } else if self.token.is_ident() && !self.token.is_any_keyword() @@ -3464,12 +3415,12 @@ impl<'a> Parser<'a> { // Potential trouble: if we allow macros with paths instead of // idents, we'd need to look ahead past the whole path here... - let pth = self.parse_path(NoTypesAllowed); - self.bump(); + let pth = try!(self.parse_path(NoTypesAllowed)); + try!(self.bump()); let id = match self.token { token::OpenDelim(_) => token::special_idents::invalid, // no special identifier - _ => self.parse_ident(), + _ => try!(self.parse_ident()), }; // check that we're pointing at delimiters (need to check @@ -3486,19 +3437,19 @@ impl<'a> Parser<'a> { "" }; let tok_str = self.this_token_to_string(); - self.fatal(&format!("expected {}`(` or `{{`, found `{}`", + return Err(self.fatal(&format!("expected {}`(` or `{{`, found `{}`", ident_str, - tok_str)) + tok_str))) }, }; - let tts = self.parse_unspanned_seq( + let tts = try!(self.parse_unspanned_seq( &token::OpenDelim(delim), &token::CloseDelim(delim), seq_sep_none(), |p| p.parse_token_tree() - ); - let hi = self.span.hi; + )); + let hi = self.last_span.hi; let style = if delim == token::Brace { MacStmtWithBraces @@ -3517,7 +3468,7 @@ impl<'a> Parser<'a> { // // Require a semicolon or braces. if style != MacStmtWithBraces { - if !self.eat(&token::Semi) { + if !try!(self.eat(&token::Semi) ){ let last_span = self.last_span; self.span_err(last_span, "macros that expand to items must \ @@ -3534,7 +3485,7 @@ impl<'a> Parser<'a> { ast::DUMMY_NODE_ID)) } } else { - match self.parse_item_(attrs, false) { + match try!(self.parse_item_(attrs, false)) { Some(i) => { let hi = i.span.hi; let decl = P(spanned(lo, hi, DeclItem(i))); @@ -3543,20 +3494,20 @@ impl<'a> Parser<'a> { None => { // Do not attempt to parse an expression if we're done here. if self.token == token::Semi { - self.bump(); - return None; + try!(self.bump()); + return Ok(None); } if self.token == token::CloseDelim(token::Brace) { - return None; + return Ok(None); } // Remainder are line-expr stmts. - let e = self.parse_expr_res(RESTRICTION_STMT_EXPR); + let e = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)) } } - }) + })) } /// Is this expression a successfully-parsed statement? @@ -3566,40 +3517,40 @@ impl<'a> Parser<'a> { } /// Parse a block. No inner attrs are allowed. - pub fn parse_block(&mut self) -> P { + pub fn parse_block(&mut self) -> PResult> { maybe_whole!(no_clone self, NtBlock); let lo = self.span.lo; - if !self.eat(&token::OpenDelim(token::Brace)) { + if !try!(self.eat(&token::OpenDelim(token::Brace)) ){ let sp = self.span; let tok = self.this_token_to_string(); - self.span_fatal_help(sp, + return Err(self.span_fatal_help(sp, &format!("expected `{{`, found `{}`", tok), - "place this code inside a block"); + "place this code inside a block")); } self.parse_block_tail(lo, DefaultBlock) } /// Parse a block. Inner attrs are allowed. - fn parse_inner_attrs_and_block(&mut self) -> (Vec, P) { + fn parse_inner_attrs_and_block(&mut self) -> PResult<(Vec, P)> { maybe_whole!(pair_empty self, NtBlock); let lo = self.span.lo; - self.expect(&token::OpenDelim(token::Brace)); - (self.parse_inner_attributes(), - self.parse_block_tail(lo, DefaultBlock)) + try!(self.expect(&token::OpenDelim(token::Brace))); + Ok((self.parse_inner_attributes(), + try!(self.parse_block_tail(lo, DefaultBlock)))) } /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> P { + fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult> { let mut stmts = vec![]; let mut expr = None; - while !self.eat(&token::CloseDelim(token::Brace)) { - let Spanned {node, span} = if let Some(s) = self.parse_stmt_() { + while !try!(self.eat(&token::CloseDelim(token::Brace))) { + let Spanned {node, span} = if let Some(s) = try!(self.parse_stmt_()) { s } else { // Found only `;` or `}`. @@ -3607,7 +3558,7 @@ impl<'a> Parser<'a> { }; match node { StmtExpr(e, _) => { - self.handle_expression_like_statement(e, span, &mut stmts, &mut expr); + try!(self.handle_expression_like_statement(e, span, &mut stmts, &mut expr)); } StmtMac(mac, MacStmtWithoutBraces) => { // statement macro without braces; might be an @@ -3616,21 +3567,21 @@ impl<'a> Parser<'a> { token::Semi => { stmts.push(P(Spanned { node: StmtMac(mac, MacStmtWithSemicolon), - span: span, + span: mk_sp(span.lo, self.span.hi), })); - self.bump(); + try!(self.bump()); } _ => { let e = self.mk_mac_expr(span.lo, span.hi, mac.and_then(|m| m.node)); - let e = self.parse_dot_or_call_expr_with(e); - let e = self.parse_more_binops(e, 0); - let e = self.parse_assign_expr_with(e); - self.handle_expression_like_statement( + let e = try!(self.parse_dot_or_call_expr_with(e)); + let e = try!(self.parse_more_binops(e, 0)); + let e = try!(self.parse_assign_expr_with(e)); + try!(self.handle_expression_like_statement( e, span, &mut stmts, - &mut expr); + &mut expr)); } } } @@ -3640,9 +3591,9 @@ impl<'a> Parser<'a> { token::Semi => { stmts.push(P(Spanned { node: StmtMac(m, MacStmtWithSemicolon), - span: span, + span: mk_sp(span.lo, self.span.hi), })); - self.bump(); + try!(self.bump()); } token::CloseDelim(token::Brace) => { // if a block ends in `m!(arg)` without @@ -3659,25 +3610,27 @@ impl<'a> Parser<'a> { } } _ => { // all other kinds of statements: + let mut hi = span.hi; if classify::stmt_ends_with_semi(&node) { - self.commit_stmt_expecting(token::Semi); + try!(self.commit_stmt_expecting(token::Semi)); + hi = self.last_span.hi; } stmts.push(P(Spanned { node: node, - span: span + span: mk_sp(span.lo, hi) })); } } } - P(ast::Block { + Ok(P(ast::Block { stmts: stmts, expr: expr, id: ast::DUMMY_NODE_ID, rules: s, span: mk_sp(lo, self.last_span.hi), - }) + })) } fn handle_expression_like_statement( @@ -3685,17 +3638,17 @@ impl<'a> Parser<'a> { e: P, span: Span, stmts: &mut Vec>, - last_block_expr: &mut Option>) { + last_block_expr: &mut Option>) -> PResult<()> { // expression without semicolon if classify::expr_requires_semi_to_be_stmt(&*e) { // Just check for errors and recover; do not eat semicolon yet. - self.commit_stmt(&[], - &[token::Semi, token::CloseDelim(token::Brace)]); + try!(self.commit_stmt(&[], + &[token::Semi, token::CloseDelim(token::Brace)])); } match self.token { token::Semi => { - self.bump(); + try!(self.bump()); let span_with_semi = Span { lo: span.lo, hi: self.last_span.hi, @@ -3714,16 +3667,17 @@ impl<'a> Parser<'a> { })); } } + Ok(()) } // Parses a sequence of bounds if a `:` is found, // otherwise returns empty list. fn parse_colon_then_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> OwnedSlice + -> PResult> { - if !self.eat(&token::Colon) { - OwnedSlice::empty() + if !try!(self.eat(&token::Colon) ){ + Ok(OwnedSlice::empty()) } else { self.parse_ty_param_bounds(mode) } @@ -3735,12 +3689,12 @@ impl<'a> Parser<'a> { // and bound = 'region | trait_ref fn parse_ty_param_bounds(&mut self, mode: BoundParsingMode) - -> OwnedSlice + -> PResult> { let mut result = vec!(); loop { let question_span = self.span; - let ate_question = self.eat(&token::Question); + let ate_question = try!(self.eat(&token::Question)); match self.token { token::Lifetime(lifetime) => { if ate_question { @@ -3752,10 +3706,10 @@ impl<'a> Parser<'a> { span: self.span, name: lifetime.name })); - self.bump(); + try!(self.bump()); } token::ModSep | token::Ident(..) => { - let poly_trait_ref = self.parse_poly_trait_ref(); + let poly_trait_ref = try!(self.parse_poly_trait_ref()); let modifier = if ate_question { if mode == BoundParsingMode::Modified { TraitBoundModifier::Maybe @@ -3772,35 +3726,35 @@ impl<'a> Parser<'a> { _ => break, } - if !self.eat(&token::BinOp(token::Plus)) { + if !try!(self.eat(&token::BinOp(token::Plus)) ){ break; } } - return OwnedSlice::from_vec(result); + return Ok(OwnedSlice::from_vec(result)); } /// Matches typaram = IDENT (`?` unbound)? optbounds ( EQ ty )? - fn parse_ty_param(&mut self) -> TyParam { + fn parse_ty_param(&mut self) -> PResult { let span = self.span; - let ident = self.parse_ident(); + let ident = try!(self.parse_ident()); - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified); + let bounds = try!(self.parse_colon_then_ty_param_bounds(BoundParsingMode::Modified)); let default = if self.check(&token::Eq) { - self.bump(); - Some(self.parse_ty_sum()) + try!(self.bump()); + Some(try!(self.parse_ty_sum())) } else { None }; - TyParam { + Ok(TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds, default: default, span: span, - } + }) } /// Parse a set of optional generic type parameter declarations. Where @@ -3810,13 +3764,13 @@ impl<'a> Parser<'a> { /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) - pub fn parse_generics(&mut self) -> ast::Generics { - if self.eat(&token::Lt) { - let lifetime_defs = self.parse_lifetime_defs(); + pub fn parse_generics(&mut self) -> PResult { + if try!(self.eat(&token::Lt) ){ + let lifetime_defs = try!(self.parse_lifetime_defs()); let mut seen_default = false; - let ty_params = self.parse_seq_to_gt(Some(token::Comma), |p| { - p.forbid_lifetime(); - let ty_param = p.parse_ty_param(); + let ty_params = try!(self.parse_seq_to_gt(Some(token::Comma), |p| { + try!(p.forbid_lifetime()); + let ty_param = try!(p.parse_ty_param()); if ty_param.default.is_some() { seen_default = true; } else if seen_default { @@ -3824,74 +3778,76 @@ impl<'a> Parser<'a> { p.span_err(last_span, "type parameters with a default must be trailing"); } - ty_param - }); - ast::Generics { + Ok(ty_param) + })); + Ok(ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params, where_clause: WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), } - } + }) } else { - ast_util::empty_generics() + Ok(ast_util::empty_generics()) } } - fn parse_generic_values_after_lt(&mut self) - -> (Vec, Vec>, Vec>) { - let lifetimes = self.parse_lifetimes(token::Comma); + fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec, + Vec>, + Vec>)> { + let lifetimes = try!(self.parse_lifetimes(token::Comma)); // First parse types. - let (types, returned) = self.parse_seq_to_gt_or_return( + let (types, returned) = try!(self.parse_seq_to_gt_or_return( Some(token::Comma), |p| { - p.forbid_lifetime(); + try!(p.forbid_lifetime()); if p.look_ahead(1, |t| t == &token::Eq) { - None + Ok(None) } else { - Some(p.parse_ty_sum()) + Ok(Some(try!(p.parse_ty_sum()))) } } - ); + )); // If we found the `>`, don't continue. if !returned { - return (lifetimes, types.into_vec(), Vec::new()); + return Ok((lifetimes, types.into_vec(), Vec::new())); } // Then parse type bindings. - let bindings = self.parse_seq_to_gt( + let bindings = try!(self.parse_seq_to_gt( Some(token::Comma), |p| { - p.forbid_lifetime(); + try!(p.forbid_lifetime()); let lo = p.span.lo; - let ident = p.parse_ident(); - let found_eq = p.eat(&token::Eq); + let ident = try!(p.parse_ident()); + let found_eq = try!(p.eat(&token::Eq)); if !found_eq { let span = p.span; p.span_warn(span, "whoops, no =?"); } - let ty = p.parse_ty(); + let ty = try!(p.parse_ty_nopanic()); let hi = p.span.hi; let span = mk_sp(lo, hi); - return P(TypeBinding{id: ast::DUMMY_NODE_ID, + return Ok(P(TypeBinding{id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, span: span, - }); + })); } - ); - (lifetimes, types.into_vec(), bindings.into_vec()) + )); + Ok((lifetimes, types.into_vec(), bindings.into_vec())) } - fn forbid_lifetime(&mut self) { + fn forbid_lifetime(&mut self) -> PResult<()> { if self.token.is_lifetime() { let span = self.span; - self.span_fatal(span, "lifetime parameters must be declared \ - prior to type parameters"); + return Err(self.span_fatal(span, "lifetime parameters must be declared \ + prior to type parameters")) } + Ok(()) } /// Parses an optional `where` clause and places it in `generics`. @@ -3899,14 +3855,14 @@ impl<'a> Parser<'a> { /// ``` /// where T : Trait + 'b, 'a : 'b /// ``` - fn parse_where_clause(&mut self) -> ast::WhereClause { + pub fn parse_where_clause(&mut self) -> PResult { let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }; - if !self.eat_keyword(keywords::Where) { - return where_clause; + if !try!(self.eat_keyword(keywords::Where)) { + return Ok(where_clause); } let mut parsed_something = false; @@ -3919,12 +3875,12 @@ impl<'a> Parser<'a> { token::Lifetime(..) => { let bounded_lifetime = - self.parse_lifetime(); + try!(self.parse_lifetime()); - self.eat(&token::Colon); + try!(self.eat(&token::Colon)); let bounds = - self.parse_lifetimes(token::BinOp(token::Plus)); + try!(self.parse_lifetimes(token::BinOp(token::Plus))); let hi = self.span.hi; let span = mk_sp(lo, hi); @@ -3941,24 +3897,24 @@ impl<'a> Parser<'a> { } _ => { - let bound_lifetimes = if self.eat_keyword(keywords::For) { + let bound_lifetimes = if try!(self.eat_keyword(keywords::For) ){ // Higher ranked constraint. - self.expect(&token::Lt); - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); + try!(self.expect(&token::Lt)); + let lifetime_defs = try!(self.parse_lifetime_defs()); + try!(self.expect_gt()); lifetime_defs } else { vec![] }; - let bounded_ty = self.parse_ty(); + let bounded_ty = try!(self.parse_ty_nopanic()); - if self.eat(&token::Colon) { - let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare); + if try!(self.eat(&token::Colon) ){ + let bounds = try!(self.parse_ty_param_bounds(BoundParsingMode::Bare)); let hi = self.span.hi; let span = mk_sp(lo, hi); - if bounds.len() == 0 { + if bounds.is_empty() { self.span_err(span, "each predicate in a `where` clause must have \ at least one bound in it"); @@ -3973,8 +3929,8 @@ impl<'a> Parser<'a> { })); parsed_something = true; - } else if self.eat(&token::Eq) { - // let ty = self.parse_ty(); + } else if try!(self.eat(&token::Eq) ){ + // let ty = try!(self.parse_ty_nopanic()); let hi = self.span.hi; let span = mk_sp(lo, hi); // where_clause.predicates.push( @@ -3997,7 +3953,7 @@ impl<'a> Parser<'a> { } }; - if !self.eat(&token::Comma) { + if !try!(self.eat(&token::Comma) ){ break } } @@ -4009,37 +3965,37 @@ impl<'a> Parser<'a> { in it"); } - where_clause + Ok(where_clause) } fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool) - -> (Vec , bool) { + -> PResult<(Vec , bool)> { let sp = self.span; let mut args: Vec> = - self.parse_unspanned_seq( + try!(self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), |p| { if p.token == token::DotDotDot { - p.bump(); + try!(p.bump()); if allow_variadic { if p.token != token::CloseDelim(token::Paren) { let span = p.span; - p.span_fatal(span, - "`...` must be last in argument list for variadic function"); + return Err(p.span_fatal(span, + "`...` must be last in argument list for variadic function")) } } else { let span = p.span; - p.span_fatal(span, - "only foreign functions are allowed to be variadic"); + return Err(p.span_fatal(span, + "only foreign functions are allowed to be variadic")) } - None + Ok(None) } else { - Some(p.parse_arg_general(named_args)) + Ok(Some(try!(p.parse_arg_general(named_args)))) } } - ); + )); let variadic = match args.pop() { Some(None) => true, @@ -4058,20 +4014,20 @@ impl<'a> Parser<'a> { let args = args.into_iter().map(|x| x.unwrap()).collect(); - (args, variadic) + Ok((args, variadic)) } /// Parse the argument list and result type of a function declaration - pub fn parse_fn_decl(&mut self, allow_variadic: bool) -> P { + pub fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult> { - let (args, variadic) = self.parse_fn_args(true, allow_variadic); - let ret_ty = self.parse_ret_ty(); + let (args, variadic) = try!(self.parse_fn_args(true, allow_variadic)); + let ret_ty = try!(self.parse_ret_ty()); - P(FnDecl { + Ok(P(FnDecl { inputs: args, output: ret_ty, variadic: variadic - }) + })) } fn is_self_ident(&mut self) -> bool { @@ -4081,16 +4037,16 @@ impl<'a> Parser<'a> { } } - fn expect_self_ident(&mut self) -> ast::Ident { + fn expect_self_ident(&mut self) -> PResult { match self.token { token::Ident(id, token::Plain) if id.name == special_idents::self_.name => { - self.bump(); - id + try!(self.bump()); + Ok(id) }, _ => { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `self`, found `{}`", - token_str)) + return Err(self.fatal(&format!("expected `self`, found `{}`", + token_str))) } } } @@ -4102,27 +4058,28 @@ impl<'a> Parser<'a> { } } - fn expect_self_type_ident(&mut self) -> ast::Ident { + fn expect_self_type_ident(&mut self) -> PResult { match self.token { token::Ident(id, token::Plain) if id.name == special_idents::type_self.name => { - self.bump(); - id + try!(self.bump()); + Ok(id) }, _ => { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `Self`, found `{}`", - token_str)) + Err(self.fatal(&format!("expected `Self`, found `{}`", + token_str))) } } } /// Parse the argument list and result type of a function /// that may have a self type. - fn parse_fn_decl_with_self(&mut self, parse_arg_fn: F) -> (ExplicitSelf, P) where - F: FnMut(&mut Parser) -> Arg, + fn parse_fn_decl_with_self(&mut self, + parse_arg_fn: F) -> PResult<(ExplicitSelf, P)> where + F: FnMut(&mut Parser) -> PResult, { fn maybe_parse_borrowed_explicit_self(this: &mut Parser) - -> ast::ExplicitSelf_ { + -> PResult { // The following things are possible to see here: // // fn(&mut self) @@ -4133,31 +4090,31 @@ impl<'a> Parser<'a> { // We already know that the current token is `&`. if this.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { - this.bump(); - SelfRegion(None, MutImmutable, this.expect_self_ident()) + try!(this.bump()); + Ok(SelfRegion(None, MutImmutable, try!(this.expect_self_ident()))) } else if this.look_ahead(1, |t| t.is_mutability()) && this.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { - this.bump(); - let mutability = this.parse_mutability(); - SelfRegion(None, mutability, this.expect_self_ident()) + try!(this.bump()); + let mutability = try!(this.parse_mutability()); + Ok(SelfRegion(None, mutability, try!(this.expect_self_ident()))) } else if this.look_ahead(1, |t| t.is_lifetime()) && this.look_ahead(2, |t| t.is_keyword(keywords::SelfValue)) { - this.bump(); - let lifetime = this.parse_lifetime(); - SelfRegion(Some(lifetime), MutImmutable, this.expect_self_ident()) + try!(this.bump()); + let lifetime = try!(this.parse_lifetime()); + Ok(SelfRegion(Some(lifetime), MutImmutable, try!(this.expect_self_ident()))) } else if this.look_ahead(1, |t| t.is_lifetime()) && this.look_ahead(2, |t| t.is_mutability()) && this.look_ahead(3, |t| t.is_keyword(keywords::SelfValue)) { - this.bump(); - let lifetime = this.parse_lifetime(); - let mutability = this.parse_mutability(); - SelfRegion(Some(lifetime), mutability, this.expect_self_ident()) + try!(this.bump()); + let lifetime = try!(this.parse_lifetime()); + let mutability = try!(this.parse_mutability()); + Ok(SelfRegion(Some(lifetime), mutability, try!(this.expect_self_ident()))) } else { - SelfStatic + Ok(SelfStatic) } } - self.expect(&token::OpenDelim(token::Paren)); + try!(self.expect(&token::OpenDelim(token::Paren))); // A bit of complexity and lookahead is needed here in order to be // backwards compatible. @@ -4168,7 +4125,7 @@ impl<'a> Parser<'a> { let mut mutbl_self = MutImmutable; let explicit_self = match self.token { token::BinOp(token::And) => { - let eself = maybe_parse_borrowed_explicit_self(self); + let eself = try!(maybe_parse_borrowed_explicit_self(self)); self_ident_lo = self.last_span.lo; self_ident_hi = self.last_span.hi; eself @@ -4176,40 +4133,40 @@ impl<'a> Parser<'a> { token::BinOp(token::Star) => { // Possibly "*self" or "*mut self" -- not supported. Try to avoid // emitting cryptic "unexpected token" errors. - self.bump(); + try!(self.bump()); let _mutability = if self.token.is_mutability() { - self.parse_mutability() + try!(self.parse_mutability()) } else { MutImmutable }; if self.is_self_ident() { let span = self.span; self.span_err(span, "cannot pass self by unsafe pointer"); - self.bump(); + try!(self.bump()); } // error case, making bogus self ident: SelfValue(special_idents::self_) } token::Ident(..) => { if self.is_self_ident() { - let self_ident = self.expect_self_ident(); + let self_ident = try!(self.expect_self_ident()); // Determine whether this is the fully explicit form, `self: // TYPE`. - if self.eat(&token::Colon) { - SelfExplicit(self.parse_ty_sum(), self_ident) + if try!(self.eat(&token::Colon) ){ + SelfExplicit(try!(self.parse_ty_sum()), self_ident) } else { SelfValue(self_ident) } } else if self.token.is_mutability() && self.look_ahead(1, |t| t.is_keyword(keywords::SelfValue)) { - mutbl_self = self.parse_mutability(); - let self_ident = self.expect_self_ident(); + mutbl_self = try!(self.parse_mutability()); + let self_ident = try!(self.expect_self_ident()); // Determine whether this is the fully explicit form, // `self: TYPE`. - if self.eat(&token::Colon) { - SelfExplicit(self.parse_ty_sum(), self_ident) + if try!(self.eat(&token::Colon) ){ + SelfExplicit(try!(self.parse_ty_sum()), self_ident) } else { SelfValue(self_ident) } @@ -4230,13 +4187,13 @@ impl<'a> Parser<'a> { // If we parsed a self type, expect a comma before the argument list. match self.token { token::Comma => { - self.bump(); + try!(self.bump()); let sep = seq_sep_trailing_allowed(token::Comma); - let mut fn_inputs = self.parse_seq_to_before_end( + let mut fn_inputs = try!(self.parse_seq_to_before_end( &token::CloseDelim(token::Paren), sep, parse_arg_fn - ); + )); fn_inputs.insert(0, Arg::new_self(explicit_self_sp, mutbl_self, $self_id)); fn_inputs } @@ -4245,8 +4202,8 @@ impl<'a> Parser<'a> { } _ => { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `,` or `)`, found `{}`", - token_str)) + return Err(self.fatal(&format!("expected `,` or `)`, found `{}`", + token_str))) } } } @@ -4255,7 +4212,8 @@ impl<'a> Parser<'a> { let fn_inputs = match explicit_self { SelfStatic => { let sep = seq_sep_trailing_allowed(token::Comma); - self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn) + try!(self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), + sep, parse_arg_fn)) } SelfValue(id) => parse_remaining_arguments!(id), SelfRegion(_,_,id) => parse_remaining_arguments!(id), @@ -4263,11 +4221,11 @@ impl<'a> Parser<'a> { }; - self.expect(&token::CloseDelim(token::Paren)); + try!(self.expect(&token::CloseDelim(token::Paren))); let hi = self.span.hi; - let ret_ty = self.parse_ret_ty(); + let ret_ty = try!(self.parse_ret_ty()); let fn_decl = P(FnDecl { inputs: fn_inputs, @@ -4275,40 +4233,40 @@ impl<'a> Parser<'a> { variadic: false }); - (spanned(lo, hi, explicit_self), fn_decl) + Ok((spanned(lo, hi, explicit_self), fn_decl)) } // parse the |arg, arg| header on a lambda - fn parse_fn_block_decl(&mut self) -> P { + fn parse_fn_block_decl(&mut self) -> PResult> { let inputs_captures = { - if self.eat(&token::OrOr) { + if try!(self.eat(&token::OrOr) ){ Vec::new() } else { - self.expect(&token::BinOp(token::Or)); - self.parse_obsolete_closure_kind(); - let args = self.parse_seq_to_before_end( + try!(self.expect(&token::BinOp(token::Or))); + try!(self.parse_obsolete_closure_kind()); + let args = try!(self.parse_seq_to_before_end( &token::BinOp(token::Or), seq_sep_trailing_allowed(token::Comma), |p| p.parse_fn_block_arg() - ); - self.bump(); + )); + try!(self.bump()); args } }; - let output = self.parse_ret_ty(); + let output = try!(self.parse_ret_ty()); - P(FnDecl { + Ok(P(FnDecl { inputs: inputs_captures, output: output, variadic: false - }) + })) } /// Parse the name and optional generic types of a function header. - fn parse_fn_header(&mut self) -> (Ident, ast::Generics) { - let id = self.parse_ident(); - let generics = self.parse_generics(); - (id, generics) + fn parse_fn_header(&mut self) -> PResult<(Ident, ast::Generics)> { + let id = try!(self.parse_ident()); + let generics = try!(self.parse_generics()); + Ok((id, generics)) } fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, @@ -4325,39 +4283,39 @@ impl<'a> Parser<'a> { } /// Parse an item-position function declaration. - fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> ItemInfo { - let (ident, mut generics) = self.parse_fn_header(); - let decl = self.parse_fn_decl(false); - generics.where_clause = self.parse_where_clause(); - let (inner_attrs, body) = self.parse_inner_attrs_and_block(); - (ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs)) + fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> PResult { + let (ident, mut generics) = try!(self.parse_fn_header()); + let decl = try!(self.parse_fn_decl(false)); + generics.where_clause = try!(self.parse_where_clause()); + let (inner_attrs, body) = try!(self.parse_inner_attrs_and_block()); + Ok((ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs))) } /// Parse an impl item. - pub fn parse_impl_item(&mut self) -> P { + pub fn parse_impl_item(&mut self) -> PResult> { let lo = self.span.lo; let mut attrs = self.parse_outer_attributes(); - let vis = self.parse_visibility(); - let (name, node) = if self.eat_keyword(keywords::Type) { - let name = self.parse_ident(); - self.expect(&token::Eq); - let typ = self.parse_ty_sum(); - self.expect(&token::Semi); + let vis = try!(self.parse_visibility()); + let (name, node) = if try!(self.eat_keyword(keywords::Type)) { + let name = try!(self.parse_ident()); + try!(self.expect(&token::Eq)); + let typ = try!(self.parse_ty_sum()); + try!(self.expect(&token::Semi)); (name, TypeImplItem(typ)) } else { - let (name, inner_attrs, node) = self.parse_impl_method(vis); + let (name, inner_attrs, node) = try!(self.parse_impl_method(vis)); attrs.extend(inner_attrs.into_iter()); (name, node) }; - P(ImplItem { + Ok(P(ImplItem { id: ast::DUMMY_NODE_ID, span: mk_sp(lo, self.last_span.hi), ident: name, vis: vis, attrs: attrs, node: node - }) + })) } fn complain_if_pub_macro(&mut self, visa: Visibility, span: Span) { @@ -4373,7 +4331,7 @@ impl<'a> Parser<'a> { /// Parse a method or a macro invocation in a trait impl. fn parse_impl_method(&mut self, vis: Visibility) - -> (Ident, Vec, ast::ImplItem_) { + -> PResult<(Ident, Vec, ast::ImplItem_)> { // code copied from parse_macro_use_or_failure... abstraction! if !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) @@ -4384,88 +4342,88 @@ impl<'a> Parser<'a> { let last_span = self.last_span; self.complain_if_pub_macro(vis, last_span); - let pth = self.parse_path(NoTypesAllowed); - self.expect(&token::Not); + let pth = try!(self.parse_path(NoTypesAllowed)); + try!(self.expect(&token::Not)); // eat a matched-delimiter token tree: - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + let delim = try!(self.expect_open_delim()); + let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim), seq_sep_none(), - |p| p.parse_token_tree()); + |p| p.parse_token_tree())); let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT); let m: ast::Mac = codemap::Spanned { node: m_, span: mk_sp(self.span.lo, self.span.hi) }; if delim != token::Brace { - self.expect(&token::Semi) + try!(self.expect(&token::Semi)) } - (token::special_idents::invalid, vec![], ast::MacImplItem(m)) + Ok((token::special_idents::invalid, vec![], ast::MacImplItem(m))) } else { - let unsafety = self.parse_unsafety(); - let abi = if self.eat_keyword(keywords::Extern) { - self.parse_opt_abi().unwrap_or(abi::C) + let unsafety = try!(self.parse_unsafety()); + let abi = if try!(self.eat_keyword(keywords::Extern)) { + try!(self.parse_opt_abi()).unwrap_or(abi::C) } else { abi::Rust }; - self.expect_keyword(keywords::Fn); - let ident = self.parse_ident(); - let mut generics = self.parse_generics(); - let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { + try!(self.expect_keyword(keywords::Fn)); + let ident = try!(self.parse_ident()); + let mut generics = try!(self.parse_generics()); + let (explicit_self, decl) = try!(self.parse_fn_decl_with_self(|p| { p.parse_arg() - }); - generics.where_clause = self.parse_where_clause(); - let (inner_attrs, body) = self.parse_inner_attrs_and_block(); - (ident, inner_attrs, MethodImplItem(ast::MethodSig { + })); + generics.where_clause = try!(self.parse_where_clause()); + let (inner_attrs, body) = try!(self.parse_inner_attrs_and_block()); + Ok((ident, inner_attrs, MethodImplItem(ast::MethodSig { generics: generics, abi: abi, explicit_self: explicit_self, unsafety: unsafety, decl: decl - }, body)) + }, body))) } } /// Parse trait Foo { ... } - fn parse_item_trait(&mut self, unsafety: Unsafety) -> ItemInfo { + fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult { - let ident = self.parse_ident(); - let mut tps = self.parse_generics(); + let ident = try!(self.parse_ident()); + let mut tps = try!(self.parse_generics()); // Parse supertrait bounds. - let bounds = self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare); + let bounds = try!(self.parse_colon_then_ty_param_bounds(BoundParsingMode::Bare)); - tps.where_clause = self.parse_where_clause(); + tps.where_clause = try!(self.parse_where_clause()); - let meths = self.parse_trait_items(); - (ident, ItemTrait(unsafety, tps, bounds, meths), None) + let meths = try!(self.parse_trait_items()); + Ok((ident, ItemTrait(unsafety, tps, bounds, meths), None)) } /// Parses items implementations variants /// impl Foo { ... } /// impl ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> ItemInfo { + fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult { let impl_span = self.span; // First, parse type parameters if necessary. - let mut generics = self.parse_generics(); + let mut generics = try!(self.parse_generics()); // Special case: if the next identifier that follows is '(', don't // allow this to be parsed as a trait. let could_be_trait = self.token != token::OpenDelim(token::Paren); let neg_span = self.span; - let polarity = if self.eat(&token::Not) { + let polarity = if try!(self.eat(&token::Not) ){ ast::ImplPolarity::Negative } else { ast::ImplPolarity::Positive }; // Parse the trait. - let mut ty = self.parse_ty_sum(); + let mut ty = try!(self.parse_ty_sum()); // Parse traits, if necessary. - let opt_trait = if could_be_trait && self.eat_keyword(keywords::For) { + let opt_trait = if could_be_trait && try!(self.eat_keyword(keywords::For) ){ // New-style trait. Reinterpret the type as a trait. match ty.node { TyPath(None, ref path) => { @@ -4491,74 +4449,74 @@ impl<'a> Parser<'a> { None }; - if self.eat(&token::DotDot) { + if try!(self.eat(&token::DotDot) ){ if generics.is_parameterized() { self.span_err(impl_span, "default trait implementations are not \ allowed to have genercis"); } - self.expect(&token::OpenDelim(token::Brace)); - self.expect(&token::CloseDelim(token::Brace)); - (ast_util::impl_pretty_name(&opt_trait, None), - ItemDefaultImpl(unsafety, opt_trait.unwrap()), None) + try!(self.expect(&token::OpenDelim(token::Brace))); + try!(self.expect(&token::CloseDelim(token::Brace))); + Ok((ast_util::impl_pretty_name(&opt_trait, None), + ItemDefaultImpl(unsafety, opt_trait.unwrap()), None)) } else { if opt_trait.is_some() { - ty = self.parse_ty_sum(); + ty = try!(self.parse_ty_sum()); } - generics.where_clause = self.parse_where_clause(); + generics.where_clause = try!(self.parse_where_clause()); - self.expect(&token::OpenDelim(token::Brace)); + try!(self.expect(&token::OpenDelim(token::Brace))); let attrs = self.parse_inner_attributes(); let mut impl_items = vec![]; - while !self.eat(&token::CloseDelim(token::Brace)) { - impl_items.push(self.parse_impl_item()); + while !try!(self.eat(&token::CloseDelim(token::Brace))) { + impl_items.push(try!(self.parse_impl_item())); } - (ast_util::impl_pretty_name(&opt_trait, Some(&*ty)), + Ok((ast_util::impl_pretty_name(&opt_trait, Some(&*ty)), ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items), - Some(attrs)) + Some(attrs))) } } /// Parse a::B - fn parse_trait_ref(&mut self) -> TraitRef { - ast::TraitRef { - path: self.parse_path(LifetimeAndTypesWithoutColons), + fn parse_trait_ref(&mut self) -> PResult { + Ok(ast::TraitRef { + path: try!(self.parse_path(LifetimeAndTypesWithoutColons)), ref_id: ast::DUMMY_NODE_ID, - } + }) } - fn parse_late_bound_lifetime_defs(&mut self) -> Vec { - if self.eat_keyword(keywords::For) { - self.expect(&token::Lt); - let lifetime_defs = self.parse_lifetime_defs(); - self.expect_gt(); - lifetime_defs + fn parse_late_bound_lifetime_defs(&mut self) -> PResult> { + if try!(self.eat_keyword(keywords::For) ){ + try!(self.expect(&token::Lt)); + let lifetime_defs = try!(self.parse_lifetime_defs()); + try!(self.expect_gt()); + Ok(lifetime_defs) } else { - Vec::new() + Ok(Vec::new()) } } /// Parse for<'l> a::B - fn parse_poly_trait_ref(&mut self) -> PolyTraitRef { + fn parse_poly_trait_ref(&mut self) -> PResult { let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs(); + let lifetime_defs = try!(self.parse_late_bound_lifetime_defs()); - ast::PolyTraitRef { + Ok(ast::PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: self.parse_trait_ref(), + trait_ref: try!(self.parse_trait_ref()), span: mk_sp(lo, self.last_span.hi), - } + }) } /// Parse struct Foo { ... } - fn parse_item_struct(&mut self) -> ItemInfo { - let class_name = self.parse_ident(); - let mut generics = self.parse_generics(); + fn parse_item_struct(&mut self) -> PResult { + let class_name = try!(self.parse_ident()); + let mut generics = try!(self.parse_generics()); - if self.eat(&token::Colon) { - let ty = self.parse_ty_sum(); + if try!(self.eat(&token::Colon) ){ + let ty = try!(self.parse_ty_sum()); self.span_err(ty.span, "`virtual` structs have been removed from the language"); } @@ -4577,66 +4535,67 @@ impl<'a> Parser<'a> { // struct. let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) { - generics.where_clause = self.parse_where_clause(); - if self.eat(&token::Semi) { + generics.where_clause = try!(self.parse_where_clause()); + if try!(self.eat(&token::Semi)) { // If we see a: `struct Foo where T: Copy;` style decl. (Vec::new(), Some(ast::DUMMY_NODE_ID)) } else { // If we see: `struct Foo where T: Copy { ... }` - (self.parse_record_struct_body(&class_name), None) + (try!(self.parse_record_struct_body(&class_name)), None) } // No `where` so: `struct Foo;` - } else if self.eat(&token::Semi) { + } else if try!(self.eat(&token::Semi) ){ (Vec::new(), Some(ast::DUMMY_NODE_ID)) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - let fields = self.parse_record_struct_body(&class_name); + let fields = try!(self.parse_record_struct_body(&class_name)); (fields, None) // Tuple-style struct definition with optional where-clause. } else { - let fields = self.parse_tuple_struct_body(&class_name, &mut generics); + let fields = try!(self.parse_tuple_struct_body(&class_name, &mut generics)); (fields, Some(ast::DUMMY_NODE_ID)) }; - (class_name, + Ok((class_name, ItemStruct(P(ast::StructDef { fields: fields, ctor_id: ctor_id, }), generics), - None) + None)) } - pub fn parse_record_struct_body(&mut self, class_name: &ast::Ident) -> Vec { + pub fn parse_record_struct_body(&mut self, + class_name: &ast::Ident) -> PResult> { let mut fields = Vec::new(); - if self.eat(&token::OpenDelim(token::Brace)) { + if try!(self.eat(&token::OpenDelim(token::Brace)) ){ while self.token != token::CloseDelim(token::Brace) { - fields.push(self.parse_struct_decl_field(true)); + fields.push(try!(self.parse_struct_decl_field(true))); } - if fields.len() == 0 { - self.fatal(&format!("unit-like struct definition should be \ + if fields.is_empty() { + return Err(self.fatal(&format!("unit-like struct definition should be \ written as `struct {};`", - token::get_ident(class_name.clone()))); + token::get_ident(class_name.clone())))); } - self.bump(); + try!(self.bump()); } else { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `where`, or `{}` after struct \ + return Err(self.fatal(&format!("expected `where`, or `{}` after struct \ name, found `{}`", "{", - token_str)); + token_str))); } - fields + Ok(fields) } pub fn parse_tuple_struct_body(&mut self, class_name: &ast::Ident, generics: &mut ast::Generics) - -> Vec { + -> PResult> { // This is the case where we find `struct Foo(T) where T: Copy;` if self.check(&token::OpenDelim(token::Paren)) { - let fields = self.parse_unspanned_seq( + let fields = try!(self.parse_unspanned_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), @@ -4644,33 +4603,33 @@ impl<'a> Parser<'a> { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; let struct_field_ = ast::StructField_ { - kind: UnnamedField(p.parse_visibility()), + kind: UnnamedField(try!(p.parse_visibility())), id: ast::DUMMY_NODE_ID, - ty: p.parse_ty_sum(), + ty: try!(p.parse_ty_sum()), attrs: attrs, }; - spanned(lo, p.span.hi, struct_field_) - }); + Ok(spanned(lo, p.span.hi, struct_field_)) + })); - if fields.len() == 0 { - self.fatal(&format!("unit-like struct definition should be \ + if fields.is_empty() { + return Err(self.fatal(&format!("unit-like struct definition should be \ written as `struct {};`", - token::get_ident(class_name.clone()))); + token::get_ident(class_name.clone())))); } - generics.where_clause = self.parse_where_clause(); - self.expect(&token::Semi); - fields + generics.where_clause = try!(self.parse_where_clause()); + try!(self.expect(&token::Semi)); + Ok(fields) // This is the case where we just see struct Foo where T: Copy; } else if self.token.is_keyword(keywords::Where) { - generics.where_clause = self.parse_where_clause(); - self.expect(&token::Semi); - Vec::new() + generics.where_clause = try!(self.parse_where_clause()); + try!(self.expect(&token::Semi)); + Ok(Vec::new()) // This case is where we see: `struct Foo;` } else { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected `where`, `{}`, `(`, or `;` after struct \ - name, found `{}`", "{", token_str)); + Err(self.fatal(&format!("expected `where`, `{}`, `(`, or `;` after struct \ + name, found `{}`", "{", token_str))) } } @@ -4678,31 +4637,31 @@ impl<'a> Parser<'a> { pub fn parse_single_struct_field(&mut self, vis: Visibility, attrs: Vec ) - -> StructField { - let a_var = self.parse_name_and_ty(vis, attrs); + -> PResult { + let a_var = try!(self.parse_name_and_ty(vis, attrs)); match self.token { token::Comma => { - self.bump(); + try!(self.bump()); } token::CloseDelim(token::Brace) => {} _ => { let span = self.span; let token_str = self.this_token_to_string(); - self.span_fatal_help(span, + return Err(self.span_fatal_help(span, &format!("expected `,`, or `}}`, found `{}`", token_str), - "struct fields should be separated by commas") + "struct fields should be separated by commas")) } } - a_var + Ok(a_var) } /// Parse an element of a struct definition - fn parse_struct_decl_field(&mut self, allow_pub: bool) -> StructField { + fn parse_struct_decl_field(&mut self, allow_pub: bool) -> PResult { let attrs = self.parse_outer_attributes(); - if self.eat_keyword(keywords::Pub) { + if try!(self.eat_keyword(keywords::Pub) ){ if !allow_pub { let span = self.last_span; self.span_err(span, "`pub` is not allowed here"); @@ -4714,63 +4673,63 @@ impl<'a> Parser<'a> { } /// Parse visibility: PUB, PRIV, or nothing - fn parse_visibility(&mut self) -> Visibility { - if self.eat_keyword(keywords::Pub) { Public } - else { Inherited } + fn parse_visibility(&mut self) -> PResult { + if try!(self.eat_keyword(keywords::Pub)) { Ok(Public) } + else { Ok(Inherited) } } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> Mod { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult { let mut items = vec![]; - while let Some(item) = self.parse_item() { + while let Some(item) = try!(self.parse_item_nopanic()) { items.push(item); } - if !self.eat(term) { + if !try!(self.eat(term)) { let token_str = self.this_token_to_string(); - self.fatal(&format!("expected item, found `{}`", token_str)) + return Err(self.fatal(&format!("expected item, found `{}`", token_str))); } - ast::Mod { + Ok(ast::Mod { inner: mk_sp(inner_lo, self.span.lo), items: items - } + }) } - fn parse_item_const(&mut self, m: Option) -> ItemInfo { - let id = self.parse_ident(); - self.expect(&token::Colon); - let ty = self.parse_ty_sum(); - self.expect(&token::Eq); - let e = self.parse_expr(); - self.commit_expr_expecting(&*e, token::Semi); + fn parse_item_const(&mut self, m: Option) -> PResult { + let id = try!(self.parse_ident()); + try!(self.expect(&token::Colon)); + let ty = try!(self.parse_ty_sum()); + try!(self.expect(&token::Eq)); + let e = try!(self.parse_expr_nopanic()); + try!(self.commit_expr_expecting(&*e, token::Semi)); let item = match m { Some(m) => ItemStatic(ty, m, e), None => ItemConst(ty, e), }; - (id, item, None) + Ok((id, item, None)) } /// Parse a `mod { ... }` or `mod ;` item - fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> ItemInfo { + fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult { let id_span = self.span; - let id = self.parse_ident(); + let id = try!(self.parse_ident()); if self.check(&token::Semi) { - self.bump(); + try!(self.bump()); // This mod is in an external file. Let's go get it! - let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span); - (id, m, Some(attrs)) + let (m, attrs) = try!(self.eval_src_mod(id, outer_attrs, id_span)); + Ok((id, m, Some(attrs))) } else { self.push_mod_path(id, outer_attrs); - self.expect(&token::OpenDelim(token::Brace)); + try!(self.expect(&token::OpenDelim(token::Brace))); let mod_inner_lo = self.span.lo; let old_owns_directory = self.owns_directory; self.owns_directory = true; let attrs = self.parse_inner_attributes(); - let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo); + let m = try!(self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)); self.owns_directory = old_owns_directory; self.pop_mod_path(); - (id, ItemMod(m), Some(attrs)) + Ok((id, ItemMod(m), Some(attrs))) } } @@ -4793,7 +4752,7 @@ impl<'a> Parser<'a> { id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) - -> (ast::Item_, Vec ) { + -> PResult<(ast::Item_, Vec )> { let mut prefix = PathBuf::from(&self.sess.span_diagnostic.cm .span_to_filename(self.span)); prefix.pop(); @@ -4840,24 +4799,24 @@ impl<'a> Parser<'a> { (true, false) => (default_path, false), (false, true) => (secondary_path, true), (false, false) => { - self.span_fatal_help(id_sp, + return Err(self.span_fatal_help(id_sp, &format!("file not found for module `{}`", mod_name), &format!("name the file either {} or {} inside \ the directory {:?}", default_path_str, secondary_path_str, - dir_path.display())); + dir_path.display()))); } (true, true) => { - self.span_fatal_help( + return Err(self.span_fatal_help( id_sp, &format!("file for module `{}` found at both {} \ and {}", mod_name, default_path_str, secondary_path_str), - "delete or rename one of them to remove the ambiguity"); + "delete or rename one of them to remove the ambiguity")); } } } @@ -4871,7 +4830,7 @@ impl<'a> Parser<'a> { path: PathBuf, owns_directory: bool, name: String, - id_sp: Span) -> (ast::Item_, Vec ) { + id_sp: Span) -> PResult<(ast::Item_, Vec )> { let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut(); match included_mod_stack.iter().position(|p| *p == path) { Some(i) => { @@ -4882,7 +4841,7 @@ impl<'a> Parser<'a> { err.push_str(" -> "); } err.push_str(&path.to_string_lossy()); - self.span_fatal(id_sp, &err[..]); + return Err(self.span_fatal(id_sp, &err[..])); } None => () } @@ -4898,53 +4857,53 @@ impl<'a> Parser<'a> { id_sp); let mod_inner_lo = p0.span.lo; let mod_attrs = p0.parse_inner_attributes(); - let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo); + let m0 = try!(p0.parse_mod_items(&token::Eof, mod_inner_lo)); self.sess.included_mod_stack.borrow_mut().pop(); - (ast::ItemMod(m0), mod_attrs) + Ok((ast::ItemMod(m0), mod_attrs)) } /// Parse a function declaration from a foreign module fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, - attrs: Vec) -> P { + attrs: Vec) -> PResult> { let lo = self.span.lo; - self.expect_keyword(keywords::Fn); + try!(self.expect_keyword(keywords::Fn)); - let (ident, mut generics) = self.parse_fn_header(); - let decl = self.parse_fn_decl(true); - generics.where_clause = self.parse_where_clause(); + let (ident, mut generics) = try!(self.parse_fn_header()); + let decl = try!(self.parse_fn_decl(true)); + generics.where_clause = try!(self.parse_where_clause()); let hi = self.span.hi; - self.expect(&token::Semi); - P(ast::ForeignItem { + try!(self.expect(&token::Semi)); + Ok(P(ast::ForeignItem { ident: ident, attrs: attrs, node: ForeignItemFn(decl, generics), id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), vis: vis - }) + })) } /// Parse a static item from a foreign module fn parse_item_foreign_static(&mut self, vis: ast::Visibility, - attrs: Vec) -> P { + attrs: Vec) -> PResult> { let lo = self.span.lo; - self.expect_keyword(keywords::Static); - let mutbl = self.eat_keyword(keywords::Mut); + try!(self.expect_keyword(keywords::Static)); + let mutbl = try!(self.eat_keyword(keywords::Mut)); - let ident = self.parse_ident(); - self.expect(&token::Colon); - let ty = self.parse_ty_sum(); + let ident = try!(self.parse_ident()); + try!(self.expect(&token::Colon)); + let ty = try!(self.parse_ty_sum()); let hi = self.span.hi; - self.expect(&token::Semi); - P(ForeignItem { + try!(self.expect(&token::Semi)); + Ok(P(ForeignItem { ident: ident, attrs: attrs, node: ForeignItemStatic(ty, mutbl), id: ast::DUMMY_NODE_ID, span: mk_sp(lo, hi), vis: vis - }) + })) } /// Parse extern crate links @@ -4957,23 +4916,23 @@ impl<'a> Parser<'a> { lo: BytePos, visibility: Visibility, attrs: Vec) - -> P { + -> PResult> { - let crate_name = self.parse_ident(); - let (maybe_path, ident) = if self.eat_keyword(keywords::As) { - (Some(crate_name.name), self.parse_ident()) + let crate_name = try!(self.parse_ident()); + let (maybe_path, ident) = if try!(self.eat_keyword(keywords::As)) { + (Some(crate_name.name), try!(self.parse_ident())) } else { (None, crate_name) }; - self.expect(&token::Semi); + try!(self.expect(&token::Semi)); let last_span = self.last_span; - self.mk_item(lo, + Ok(self.mk_item(lo, last_span.hi, ident, ItemExternCrate(maybe_path), visibility, - attrs) + attrs)) } /// Parse `extern` for foreign ABIs @@ -4991,60 +4950,60 @@ impl<'a> Parser<'a> { opt_abi: Option, visibility: Visibility, mut attrs: Vec) - -> P { - self.expect(&token::OpenDelim(token::Brace)); + -> PResult> { + try!(self.expect(&token::OpenDelim(token::Brace))); let abi = opt_abi.unwrap_or(abi::C); attrs.extend(self.parse_inner_attributes().into_iter()); let mut foreign_items = vec![]; - while let Some(item) = self.parse_foreign_item() { + while let Some(item) = try!(self.parse_foreign_item()) { foreign_items.push(item); } - self.expect(&token::CloseDelim(token::Brace)); + try!(self.expect(&token::CloseDelim(token::Brace))); let last_span = self.last_span; let m = ast::ForeignMod { abi: abi, items: foreign_items }; - self.mk_item(lo, + Ok(self.mk_item(lo, last_span.hi, special_idents::invalid, ItemForeignMod(m), visibility, - attrs) + attrs)) } /// Parse type Foo = Bar; - fn parse_item_type(&mut self) -> ItemInfo { - let ident = self.parse_ident(); - let mut tps = self.parse_generics(); - tps.where_clause = self.parse_where_clause(); - self.expect(&token::Eq); - let ty = self.parse_ty_sum(); - self.expect(&token::Semi); - (ident, ItemTy(ty, tps), None) + fn parse_item_type(&mut self) -> PResult { + let ident = try!(self.parse_ident()); + let mut tps = try!(self.parse_generics()); + tps.where_clause = try!(self.parse_where_clause()); + try!(self.expect(&token::Eq)); + let ty = try!(self.parse_ty_sum()); + try!(self.expect(&token::Semi)); + Ok((ident, ItemTy(ty, tps), None)) } /// Parse a structure-like enum variant definition /// this should probably be renamed or refactored... - fn parse_struct_def(&mut self) -> P { + fn parse_struct_def(&mut self) -> PResult> { let mut fields: Vec = Vec::new(); while self.token != token::CloseDelim(token::Brace) { - fields.push(self.parse_struct_decl_field(false)); + fields.push(try!(self.parse_struct_decl_field(false))); } - self.bump(); + try!(self.bump()); - P(StructDef { + Ok(P(StructDef { fields: fields, ctor_id: None, - }) + })) } /// Parse the part of an "enum" decl following the '{' - fn parse_enum_def(&mut self, _generics: &ast::Generics) -> EnumDef { + fn parse_enum_def(&mut self, _generics: &ast::Generics) -> PResult { let mut variants = Vec::new(); let mut all_nullary = true; let mut any_disr = None; @@ -5052,19 +5011,19 @@ impl<'a> Parser<'a> { let variant_attrs = self.parse_outer_attributes(); let vlo = self.span.lo; - let vis = self.parse_visibility(); + let vis = try!(self.parse_visibility()); let ident; let kind; let mut args = Vec::new(); let mut disr_expr = None; - ident = self.parse_ident(); - if self.eat(&token::OpenDelim(token::Brace)) { + ident = try!(self.parse_ident()); + if try!(self.eat(&token::OpenDelim(token::Brace)) ){ // Parse a struct variant. all_nullary = false; let start_span = self.span; - let struct_def = self.parse_struct_def(); - if struct_def.fields.len() == 0 { + let struct_def = try!(self.parse_struct_def()); + if struct_def.fields.is_empty() { self.span_err(start_span, &format!("unit-like struct variant should be written \ without braces, as `{},`", @@ -5073,12 +5032,12 @@ impl<'a> Parser<'a> { kind = StructVariantKind(struct_def); } else if self.check(&token::OpenDelim(token::Paren)) { all_nullary = false; - let arg_tys = self.parse_enum_variant_seq( + let arg_tys = try!(self.parse_enum_variant_seq( &token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), seq_sep_trailing_allowed(token::Comma), |p| p.parse_ty_sum() - ); + )); for ty in arg_tys { args.push(ast::VariantArg { ty: ty, @@ -5086,8 +5045,8 @@ impl<'a> Parser<'a> { }); } kind = TupleVariantKind(args); - } else if self.eat(&token::Eq) { - disr_expr = Some(self.parse_expr()); + } else if try!(self.eat(&token::Eq) ){ + disr_expr = Some(try!(self.parse_expr_nopanic())); any_disr = disr_expr.as_ref().map(|expr| expr.span); kind = TupleVariantKind(args); } else { @@ -5104,9 +5063,9 @@ impl<'a> Parser<'a> { }; variants.push(P(spanned(vlo, self.last_span.hi, vr))); - if !self.eat(&token::Comma) { break; } + if !try!(self.eat(&token::Comma)) { break; } } - self.expect(&token::CloseDelim(token::Brace)); + try!(self.expect(&token::CloseDelim(token::Brace))); match any_disr { Some(disr_span) if !all_nullary => self.span_err(disr_span, @@ -5114,31 +5073,31 @@ impl<'a> Parser<'a> { _ => () } - ast::EnumDef { variants: variants } + Ok(ast::EnumDef { variants: variants }) } /// Parse an "enum" declaration - fn parse_item_enum(&mut self) -> ItemInfo { - let id = self.parse_ident(); - let mut generics = self.parse_generics(); - generics.where_clause = self.parse_where_clause(); - self.expect(&token::OpenDelim(token::Brace)); + fn parse_item_enum(&mut self) -> PResult { + let id = try!(self.parse_ident()); + let mut generics = try!(self.parse_generics()); + generics.where_clause = try!(self.parse_where_clause()); + try!(self.expect(&token::OpenDelim(token::Brace))); - let enum_definition = self.parse_enum_def(&generics); - (id, ItemEnum(enum_definition, generics), None) + let enum_definition = try!(self.parse_enum_def(&generics)); + Ok((id, ItemEnum(enum_definition, generics), None)) } /// Parses a string as an ABI spec on an extern type or module. Consumes /// the `extern` keyword, if one is found. - fn parse_opt_abi(&mut self) -> Option { + fn parse_opt_abi(&mut self) -> PResult> { match self.token { token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { let sp = self.span; self.expect_no_suffix(sp, "ABI spec", suf); - self.bump(); + try!(self.bump()); let the_string = s.as_str(); match abi::lookup(the_string) { - Some(abi) => Some(abi), + Some(abi) => Ok(Some(abi)), None => { let last_span = self.last_span; self.span_err( @@ -5147,12 +5106,12 @@ impl<'a> Parser<'a> { found `{}`", abi::all_names().connect(", "), the_string)); - None + Ok(None) } } } - _ => None, + _ => Ok(None), } } @@ -5160,7 +5119,7 @@ impl<'a> Parser<'a> { /// NB: this function no longer parses the items inside an /// extern crate. fn parse_item_(&mut self, attrs: Vec, - macros_allowed: bool) -> Option> { + macros_allowed: bool) -> PResult>> { let nt_item = match self.token { token::Interpolated(token::NtItem(ref item)) => { Some((**item).clone()) @@ -5169,23 +5128,23 @@ impl<'a> Parser<'a> { }; match nt_item { Some(mut item) => { - self.bump(); + try!(self.bump()); let mut attrs = attrs; mem::swap(&mut item.attrs, &mut attrs); item.attrs.extend(attrs.into_iter()); - return Some(P(item)); + return Ok(Some(P(item))); } None => {} } let lo = self.span.lo; - let visibility = self.parse_visibility(); + let visibility = try!(self.parse_visibility()); - if self.eat_keyword(keywords::Use) { + if try!(self.eat_keyword(keywords::Use) ){ // USE ITEM - let item_ = ItemUse(self.parse_view_path()); - self.expect(&token::Semi); + let item_ = ItemUse(try!(self.parse_view_path())); + try!(self.expect(&token::Semi)); let last_span = self.last_span; let item = self.mk_item(lo, @@ -5194,21 +5153,21 @@ impl<'a> Parser<'a> { item_, visibility, attrs); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Extern) { - if self.eat_keyword(keywords::Crate) { - return Some(self.parse_item_extern_crate(lo, visibility, attrs)); + if try!(self.eat_keyword(keywords::Extern)) { + if try!(self.eat_keyword(keywords::Crate)) { + return Ok(Some(try!(self.parse_item_extern_crate(lo, visibility, attrs)))); } - let opt_abi = self.parse_opt_abi(); + let opt_abi = try!(self.parse_opt_abi()); - if self.eat_keyword(keywords::Fn) { + if try!(self.eat_keyword(keywords::Fn) ){ // EXTERN FUNCTION ITEM let abi = opt_abi.unwrap_or(abi::C); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, abi); + try!(self.parse_item_fn(Unsafety::Normal, abi)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5216,27 +5175,27 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } else if self.check(&token::OpenDelim(token::Brace)) { - return Some(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs)); + return Ok(Some(try!(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs)))); } let span = self.span; let token_str = self.this_token_to_string(); - self.span_fatal(span, + return Err(self.span_fatal(span, &format!("expected `{}` or `fn`, found `{}`", "{", - token_str)); + token_str))) } - if self.eat_keyword_noexpect(keywords::Virtual) { + if try!(self.eat_keyword_noexpect(keywords::Virtual) ){ let span = self.span; self.span_err(span, "`virtual` structs have been removed from the language"); } - if self.eat_keyword(keywords::Static) { + if try!(self.eat_keyword(keywords::Static) ){ // STATIC ITEM - let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable}; - let (ident, item_, extra_attrs) = self.parse_item_const(Some(m)); + let m = if try!(self.eat_keyword(keywords::Mut)) {MutMutable} else {MutImmutable}; + let (ident, item_, extra_attrs) = try!(self.parse_item_const(Some(m))); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5244,16 +5203,16 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Const) { + if try!(self.eat_keyword(keywords::Const) ){ // CONST ITEM - if self.eat_keyword(keywords::Mut) { + if try!(self.eat_keyword(keywords::Mut) ){ let last_span = self.last_span; self.span_err(last_span, "const globals cannot be mutable"); self.fileline_help(last_span, "did you mean to declare a static?"); } - let (ident, item_, extra_attrs) = self.parse_item_const(None); + let (ident, item_, extra_attrs) = try!(self.parse_item_const(None)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5261,16 +5220,16 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) { // UNSAFE TRAIT ITEM - self.expect_keyword(keywords::Unsafe); - self.expect_keyword(keywords::Trait); + try!(self.expect_keyword(keywords::Unsafe)); + try!(self.expect_keyword(keywords::Trait)); let (ident, item_, extra_attrs) = - self.parse_item_trait(ast::Unsafety::Unsafe); + try!(self.parse_item_trait(ast::Unsafety::Unsafe)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5278,15 +5237,15 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) { // IMPL ITEM - self.expect_keyword(keywords::Unsafe); - self.expect_keyword(keywords::Impl); - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe); + try!(self.expect_keyword(keywords::Unsafe)); + try!(self.expect_keyword(keywords::Impl)); + let (ident, item_, extra_attrs) = try!(self.parse_item_impl(ast::Unsafety::Unsafe)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5294,13 +5253,13 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } if self.check_keyword(keywords::Fn) { // FUNCTION ITEM - self.bump(); + try!(self.bump()); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, abi::Rust); + try!(self.parse_item_fn(Unsafety::Normal, abi::Rust)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5308,20 +5267,20 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { // UNSAFE FUNCTION ITEM - self.bump(); - let abi = if self.eat_keyword(keywords::Extern) { - self.parse_opt_abi().unwrap_or(abi::C) + try!(self.bump()); + let abi = if try!(self.eat_keyword(keywords::Extern) ){ + try!(self.parse_opt_abi()).unwrap_or(abi::C) } else { abi::Rust }; - self.expect_keyword(keywords::Fn); + try!(self.expect_keyword(keywords::Fn)); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, abi); + try!(self.parse_item_fn(Unsafety::Unsafe, abi)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5329,12 +5288,12 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Mod) { + if try!(self.eat_keyword(keywords::Mod) ){ // MODULE ITEM let (ident, item_, extra_attrs) = - self.parse_item_mod(&attrs[..]); + try!(self.parse_item_mod(&attrs[..])); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5342,11 +5301,11 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Type) { + if try!(self.eat_keyword(keywords::Type) ){ // TYPE ITEM - let (ident, item_, extra_attrs) = self.parse_item_type(); + let (ident, item_, extra_attrs) = try!(self.parse_item_type()); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5354,11 +5313,11 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Enum) { + if try!(self.eat_keyword(keywords::Enum) ){ // ENUM ITEM - let (ident, item_, extra_attrs) = self.parse_item_enum(); + let (ident, item_, extra_attrs) = try!(self.parse_item_enum()); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5366,12 +5325,12 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Trait) { + if try!(self.eat_keyword(keywords::Trait) ){ // TRAIT ITEM let (ident, item_, extra_attrs) = - self.parse_item_trait(ast::Unsafety::Normal); + try!(self.parse_item_trait(ast::Unsafety::Normal)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5379,11 +5338,11 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Impl) { + if try!(self.eat_keyword(keywords::Impl) ){ // IMPL ITEM - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal); + let (ident, item_, extra_attrs) = try!(self.parse_item_impl(ast::Unsafety::Normal)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5391,11 +5350,11 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } - if self.eat_keyword(keywords::Struct) { + if try!(self.eat_keyword(keywords::Struct) ){ // STRUCT ITEM - let (ident, item_, extra_attrs) = self.parse_item_struct(); + let (ident, item_, extra_attrs) = try!(self.parse_item_struct()); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5403,33 +5362,33 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Some(item); + return Ok(Some(item)); } self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility) } /// Parse a foreign item. - fn parse_foreign_item(&mut self) -> Option> { + fn parse_foreign_item(&mut self) -> PResult>> { let lo = self.span.lo; let attrs = self.parse_outer_attributes(); - let visibility = self.parse_visibility(); + let visibility = try!(self.parse_visibility()); if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM - return Some(self.parse_item_foreign_static(visibility, attrs)); + return Ok(Some(try!(self.parse_item_foreign_static(visibility, attrs)))); } if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) { // FOREIGN FUNCTION ITEM - return Some(self.parse_item_foreign_fn(visibility, attrs)); + return Ok(Some(try!(self.parse_item_foreign_fn(visibility, attrs)))); } // FIXME #5668: this will occur for a macro invocation: - match self.parse_macro_use_or_failure(attrs, true, lo, visibility) { + match try!(self.parse_macro_use_or_failure(attrs, true, lo, visibility)) { Some(item) => { - self.span_fatal(item.span, "macros cannot expand to foreign items"); + return Err(self.span_fatal(item.span, "macros cannot expand to foreign items")); } - None => None + None => Ok(None) } } @@ -5440,7 +5399,7 @@ impl<'a> Parser<'a> { macros_allowed: bool, lo: BytePos, visibility: Visibility - ) -> Option> { + ) -> PResult>> { if macros_allowed && !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) && (self.look_ahead(2, |t| t.is_plain_ident()) @@ -5452,22 +5411,22 @@ impl<'a> Parser<'a> { self.complain_if_pub_macro(visibility, last_span); // item macro. - let pth = self.parse_path(NoTypesAllowed); - self.expect(&token::Not); + let pth = try!(self.parse_path(NoTypesAllowed)); + try!(self.expect(&token::Not)); // a 'special' identifier (like what `macro_rules!` uses) // is optional. We should eventually unify invoc syntax // and remove this. let id = if self.token.is_plain_ident() { - self.parse_ident() + try!(self.parse_ident()) } else { token::special_idents::invalid // no special identifier }; // eat a matched-delimiter token tree: - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + let delim = try!(self.expect_open_delim()); + let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim), seq_sep_none(), - |p| p.parse_token_tree()); + |p| p.parse_token_tree())); // single-variant-enum... : let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT); let m: ast::Mac = codemap::Spanned { node: m, @@ -5475,7 +5434,7 @@ impl<'a> Parser<'a> { self.span.hi) }; if delim != token::Brace { - if !self.eat(&token::Semi) { + if !try!(self.eat(&token::Semi) ){ let last_span = self.last_span; self.span_err(last_span, "macros that expand to items must either \ @@ -5492,7 +5451,7 @@ impl<'a> Parser<'a> { item_, visibility, attrs); - return Some(item); + return Ok(Some(item)); } // FAILURE TO PARSE ITEM @@ -5500,69 +5459,70 @@ impl<'a> Parser<'a> { Inherited => {} Public => { let last_span = self.last_span; - self.span_fatal(last_span, "unmatched visibility `pub`"); + return Err(self.span_fatal(last_span, "unmatched visibility `pub`")); } } if !attrs.is_empty() { self.expected_item_err(&attrs); } - None + Ok(None) } - pub fn parse_item(&mut self) -> Option> { + pub fn parse_item_nopanic(&mut self) -> PResult>> { let attrs = self.parse_outer_attributes(); self.parse_item_(attrs, true) } + /// Matches view_path : MOD? non_global_path as IDENT /// | MOD? non_global_path MOD_SEP LBRACE RBRACE /// | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE /// | MOD? non_global_path MOD_SEP STAR /// | MOD? non_global_path - fn parse_view_path(&mut self) -> P { + fn parse_view_path(&mut self) -> PResult> { let lo = self.span.lo; // Allow a leading :: because the paths are absolute either way. // This occurs with "use $crate::..." in macros. - self.eat(&token::ModSep); + try!(self.eat(&token::ModSep)); if self.check(&token::OpenDelim(token::Brace)) { // use {foo,bar} - let idents = self.parse_unspanned_seq( + let idents = try!(self.parse_unspanned_seq( &token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), seq_sep_trailing_allowed(token::Comma), - |p| p.parse_path_list_item()); + |p| p.parse_path_list_item())); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, segments: Vec::new() }; - return P(spanned(lo, self.span.hi, ViewPathList(path, idents))); + return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents)))); } - let first_ident = self.parse_ident(); + let first_ident = try!(self.parse_ident()); let mut path = vec!(first_ident); if let token::ModSep = self.token { // foo::bar or foo::{a,b,c} or foo::* while self.check(&token::ModSep) { - self.bump(); + try!(self.bump()); match self.token { token::Ident(..) => { - let ident = self.parse_ident(); + let ident = try!(self.parse_ident()); path.push(ident); } // foo::bar::{a,b,c} token::OpenDelim(token::Brace) => { - let idents = self.parse_unspanned_seq( + let idents = try!(self.parse_unspanned_seq( &token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), seq_sep_trailing_allowed(token::Comma), |p| p.parse_path_list_item() - ); + )); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, @@ -5573,12 +5533,12 @@ impl<'a> Parser<'a> { } }).collect() }; - return P(spanned(lo, self.span.hi, ViewPathList(path, idents))); + return Ok(P(spanned(lo, self.span.hi, ViewPathList(path, idents)))); } // foo::bar::* token::BinOp(token::Star) => { - self.bump(); + try!(self.bump()); let path = ast::Path { span: mk_sp(lo, self.span.hi), global: false, @@ -5589,7 +5549,7 @@ impl<'a> Parser<'a> { } }).collect() }; - return P(spanned(lo, self.span.hi, ViewPathGlob(path))); + return Ok(P(spanned(lo, self.span.hi, ViewPathGlob(path)))); } // fall-through for case foo::bar::; @@ -5612,27 +5572,29 @@ impl<'a> Parser<'a> { } }).collect() }; - if self.eat_keyword(keywords::As) { - rename_to = self.parse_ident() + if try!(self.eat_keyword(keywords::As)) { + rename_to = try!(self.parse_ident()) } - P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path))) + Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path)))) } /// Parses a source module as a crate. This is the main /// entry point for the parser. - pub fn parse_crate_mod(&mut self) -> Crate { + pub fn parse_crate_mod(&mut self) -> PResult { let lo = self.span.lo; - ast::Crate { + Ok(ast::Crate { attrs: self.parse_inner_attributes(), - module: self.parse_mod_items(&token::Eof, lo), + module: try!(self.parse_mod_items(&token::Eof, lo)), config: self.cfg.clone(), span: mk_sp(lo, self.span.lo), exported_macros: Vec::new(), - } + }) } pub fn parse_optional_str(&mut self) - -> Option<(InternedString, ast::StrStyle, Option)> { + -> PResult)>> { let ret = match self.token { token::Literal(token::Str_(s), suf) => { (self.id_to_interned_str(s.ident()), ast::CookedStr, suf) @@ -5640,20 +5602,20 @@ impl<'a> Parser<'a> { token::Literal(token::StrRaw(s, n), suf) => { (self.id_to_interned_str(s.ident()), ast::RawStr(n), suf) } - _ => return None + _ => return Ok(None) }; - self.bump(); - Some(ret) + try!(self.bump()); + Ok(Some(ret)) } - pub fn parse_str(&mut self) -> (InternedString, StrStyle) { - match self.parse_optional_str() { + pub fn parse_str(&mut self) -> PResult<(InternedString, StrStyle)> { + match try!(self.parse_optional_str()) { Some((s, style, suf)) => { let sp = self.last_span; self.expect_no_suffix(sp, "str literal", suf); - (s, style) + Ok((s, style)) } - _ => self.fatal("expected string literal") + _ => Err(self.fatal("expected string literal")) } } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 4db85eeea4..2bb74944ce 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -23,10 +23,7 @@ use util::interner; use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; -use std::mem; use std::ops::Deref; -#[allow(deprecated)] -use std::old_path::BytesContainer; use std::rc::Rc; #[allow(non_camel_case_types)] @@ -639,19 +636,6 @@ impl Deref for InternedString { fn deref(&self) -> &str { &*self.string } } -#[allow(deprecated)] -impl BytesContainer for InternedString { - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - // FIXME #12938: This is a workaround for the incorrect signature - // of `BytesContainer`, which is itself a workaround for the lack of - // DST. - unsafe { - let this = &self[..]; - mem::transmute::<&[u8],&[u8]>(this.container_as_bytes()) - } - } -} - impl fmt::Debug for InternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.string, f) diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index ebfd970f3d..3fd4e31b47 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -565,7 +565,7 @@ impl<'a> Printer<'a> { Token::End => { debug!("print End -> pop End"); let print_stack = &mut self.print_stack; - assert!((print_stack.len() != 0)); + assert!((!print_stack.is_empty())); print_stack.pop().unwrap(); Ok(()) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 46d196d13f..c51b5d0397 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -352,6 +352,10 @@ pub fn stmt_to_string(stmt: &ast::Stmt) -> String { $to_string(|s| s.print_stmt(stmt)) } +pub fn attr_to_string(attr: &ast::Attribute) -> String { + $to_string(|s| s.print_attribute(attr)) +} + pub fn item_to_string(i: &ast::Item) -> String { $to_string(|s| s.print_item(i)) } @@ -1652,7 +1656,7 @@ impl<'a> State<'a> { try!(self.print_expr(&*args[0])); try!(word(&mut self.s, ".")); try!(self.print_ident(ident.node)); - if tys.len() > 0 { + if !tys.is_empty() { try!(word(&mut self.s, "::<")); try!(self.commasep(Inconsistent, tys, |s, ty| s.print_type(&**ty))); @@ -1952,7 +1956,7 @@ impl<'a> State<'a> { options.push("intel"); } - if options.len() > 0 { + if !options.is_empty() { try!(space(&mut self.s)); try!(self.word_space(":")); try!(self.commasep(Inconsistent, &*options, @@ -2210,7 +2214,7 @@ impl<'a> State<'a> { }, |f| f.node.pat.span)); if etc { - if fields.len() != 0 { try!(self.word_space(",")); } + if !fields.is_empty() { try!(self.word_space(",")); } try!(word(&mut self.s, "..")); } try!(space(&mut self.s)); @@ -2542,7 +2546,7 @@ impl<'a> State<'a> { pub fn print_where_clause(&mut self, where_clause: &ast::WhereClause) -> io::Result<()> { - if where_clause.predicates.len() == 0 { + if where_clause.predicates.is_empty() { return Ok(()) } @@ -2723,7 +2727,7 @@ impl<'a> State<'a> { opt_explicit_self: Option<&ast::ExplicitSelf_>) -> io::Result<()> { try!(self.ibox(indent_unit)); - if generics.lifetimes.len() > 0 || generics.ty_params.len() > 0 { + if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { try!(word(&mut self.s, "for")); try!(self.print_generics(generics)); } diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 7e0bcd3e1d..5032cd57ee 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -111,6 +111,13 @@ impl Display for P { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for P { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&self.ptr, f) + } +} + impl Hash for P { fn hash(&self, state: &mut H) { (**self).hash(state); diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fbee11ee65..a3cfb64785 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -125,7 +125,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { match i.node { ast::ItemFn(_, ast::Unsafety::Unsafe, _, _, _) => { let diag = self.cx.span_diagnostic; - diag.span_fatal(i.span, "unsafe functions cannot be used for tests"); + panic!(diag.span_fatal(i.span, "unsafe functions cannot be used for tests")); } _ => { debug!("this is a test function"); diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index ec60864632..c6646fe93a 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -44,7 +44,7 @@ fn with_error_checking_parse(s: String, f: F) -> T where /// Parse a string, return a crate. pub fn string_to_crate (source_str : String) -> ast::Crate { with_error_checking_parse(source_str, |p| { - p.parse_crate_mod() + panictry!(p.parse_crate_mod()) }) } diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 1649934f4b..6b864d5294 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -69,6 +69,20 @@ impl SmallVector { } } + pub fn pop(&mut self) -> Option { + match self.repr { + Zero => None, + One(..) => { + let one = mem::replace(&mut self.repr, Zero); + match one { + One(v1) => Some(v1), + _ => unreachable!() + } + } + Many(ref mut vs) => vs.pop(), + } + } + pub fn push(&mut self, v: T) { match self.repr { Zero => self.repr = One(v), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 5c345c7564..4c70fc9f81 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -35,10 +35,10 @@ use owned_slice::OwnedSlice; #[derive(Copy, Clone)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - FkItemFn(Ident, &'a Generics, Unsafety, Abi), + FkItemFn(Ident, &'a Generics, Unsafety, Abi, Visibility), /// fn foo(&self) - FkMethod(Ident, &'a MethodSig), + FkMethod(Ident, &'a MethodSig, Option), /// |x, y| ... /// proc(x, y) ... @@ -247,7 +247,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_expr(&**expr); } ItemFn(ref declaration, fn_style, abi, ref generics, ref body) => { - visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi), + visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi, item.vis), &**declaration, &**body, item.span, @@ -600,10 +600,10 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, walk_fn_decl(visitor, function_declaration); match function_kind { - FkItemFn(_, generics, _, _) => { + FkItemFn(_, generics, _, _, _) => { visitor.visit_generics(generics); } - FkMethod(_, sig) => { + FkMethod(_, sig, _) => { visitor.visit_generics(&sig.generics); visitor.visit_explicit_self(&sig.explicit_self); } @@ -625,7 +625,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai walk_fn_decl(visitor, &sig.decl); } MethodTraitItem(ref sig, Some(ref body)) => { - visitor.visit_fn(FkMethod(trait_item.ident, sig), &sig.decl, + visitor.visit_fn(FkMethod(trait_item.ident, sig, None), &sig.decl, body, trait_item.span, trait_item.id); } TypeTraitItem(ref bounds, ref default) => { @@ -642,7 +642,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt } match impl_item.node { MethodImplItem(ref sig, ref body) => { - visitor.visit_fn(FkMethod(impl_item.ident, sig), &sig.decl, + visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl, body, impl_item.span, impl_item.id); } TypeImplItem(ref ty) => { diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index 01586b8f36..c9ad08bb85 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -123,7 +123,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Percent => { match cur { '%' => { output.push(c); state = Nothing }, - 'c' => if stack.len() > 0 { + 'c' => if !stack.is_empty() { match stack.pop().unwrap() { // if c is 0, use 0200 (128) for ncurses compatibility Number(c) => { @@ -141,7 +141,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) 'g' => state = GetVar, '\'' => state = CharConstant, '{' => state = IntConstant(0), - 'l' => if stack.len() > 0 { + 'l' => if !stack.is_empty() { match stack.pop().unwrap() { Words(s) => stack.push(Number(s.len() as isize)), _ => return Err("a non-str was used with %l".to_string()) @@ -231,14 +231,14 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) _ => return Err("non-numbers on stack with logical or".to_string()) } } else { return Err("stack is empty".to_string()) }, - '!' => if stack.len() > 0 { + '!' => if !stack.is_empty() { match stack.pop().unwrap() { Number(0) => stack.push(Number(1)), Number(_) => stack.push(Number(0)), _ => return Err("non-number on stack with logical not".to_string()) } } else { return Err("stack is empty".to_string()) }, - '~' => if stack.len() > 0 { + '~' => if !stack.is_empty() { match stack.pop().unwrap() { Number(x) => stack.push(Number(!x)), _ => return Err("non-number on stack with %~".to_string()) @@ -253,7 +253,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) }, // printf-style support for %doxXs - 'd'|'o'|'x'|'X'|'s' => if stack.len() > 0 { + 'd'|'o'|'x'|'X'|'s' => if !stack.is_empty() { let flags = Flags::new(); let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags); if res.is_err() { return res } @@ -278,7 +278,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) // conditionals '?' => (), - 't' => if stack.len() > 0 { + 't' => if !stack.is_empty() { match stack.pop().unwrap() { Number(0) => state = SeekIfElse(0), Number(_) => (), @@ -303,12 +303,12 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) }, SetVar => { if cur >= 'A' && cur <= 'Z' { - if stack.len() > 0 { + if !stack.is_empty() { let idx = (cur as u8) - b'A'; vars.sta[idx as usize] = stack.pop().unwrap(); } else { return Err("stack is empty".to_string()) } } else if cur >= 'a' && cur <= 'z' { - if stack.len() > 0 { + if !stack.is_empty() { let idx = (cur as u8) - b'a'; vars.dyn[idx as usize] = stack.pop().unwrap(); } else { return Err("stack is empty".to_string()) } @@ -352,7 +352,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) FormatPattern(ref mut flags, ref mut fstate) => { old_state = Nothing; match (*fstate, cur) { - (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if stack.len() > 0 { + (_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if !stack.is_empty() { let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), *flags); if res.is_err() { return res } output.push_all(&res.unwrap()); diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs index 3083f8e892..16062060df 100644 --- a/src/libterm/terminfo/searcher.rs +++ b/src/libterm/terminfo/searcher.rs @@ -20,7 +20,7 @@ use std::path::PathBuf; /// Return path to database entry for `term` #[allow(deprecated)] pub fn get_dbpath_for_term(term: &str) -> Option> { - if term.len() == 0 { + if term.is_empty() { return None; } diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index c84703b93e..9dd903b769 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -75,7 +75,6 @@ use std::fs::File; use std::io::prelude::*; use std::io; use std::iter::repeat; -use std::num::{Float, Int}; use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; @@ -373,7 +372,7 @@ pub fn parse_opts(args: &[String]) -> Option { if matches.opt_present("h") { usage(&args[0]); return None; } - let filter = if matches.free.len() > 0 { + let filter = if !matches.free.is_empty() { Some(matches.free[0].clone()) } else { None @@ -418,7 +417,7 @@ pub fn parse_opts(args: &[String]) -> Option { #[derive(Clone, PartialEq)] pub struct BenchSamples { - ns_iter_summ: stats::Summary, + ns_iter_summ: stats::Summary, mb_s: usize, } @@ -588,14 +587,14 @@ impl ConsoleTestState { let mut fail_out = String::new(); for &(ref f, ref stdout) in &self.failures { failures.push(f.name.to_string()); - if stdout.len() > 0 { + if !stdout.is_empty() { fail_out.push_str(&format!("---- {} stdout ----\n\t", f.name)); let output = String::from_utf8_lossy(stdout); fail_out.push_str(&output); fail_out.push_str("\n"); } } - if fail_out.len() > 0 { + if !fail_out.is_empty() { try!(self.write_plain("\n")); try!(self.write_plain(&fail_out)); } @@ -1071,7 +1070,7 @@ impl Bencher { } // This is a more statistics-driven benchmark algorithm - pub fn auto_bench(&mut self, mut f: F) -> stats::Summary where F: FnMut(&mut Bencher) { + pub fn auto_bench(&mut self, mut f: F) -> stats::Summary where F: FnMut(&mut Bencher) { // Initial bench run to get ballpark figure. let mut n = 1; self.bench_n(n, |x| f(x)); diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 94dee5ccc3..c1ba1260f6 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -13,9 +13,8 @@ use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::mem; -use std::num::{Float, FromPrimitive}; -fn local_cmp(x: T, y: T) -> Ordering { +fn local_cmp(x: f64, y: f64) -> Ordering { // arbitrarily decide that NaNs are larger than everything. if y.is_nan() { Less @@ -30,12 +29,12 @@ fn local_cmp(x: T, y: T) -> Ordering { } } -fn local_sort(v: &mut [T]) { - v.sort_by(|x: &T, y: &T| local_cmp(*x, *y)); +fn local_sort(v: &mut [f64]) { + v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. -pub trait Stats { +pub trait Stats { /// Sum of the samples. /// @@ -43,25 +42,24 @@ pub trait Stats { /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"] /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps) - /// *Discrete & Computational Geometry 18*, 3 (Oct 1997), 305-363, Shewchuk J.R. - fn sum(&self) -> T; + fn sum(&self) -> f64; /// Minimum value of the samples. - fn min(&self) -> T; + fn min(&self) -> f64; /// Maximum value of the samples. - fn max(&self) -> T; + fn max(&self) -> f64; /// Arithmetic mean (average) of the samples: sum divided by sample-count. /// /// See: https://en.wikipedia.org/wiki/Arithmetic_mean - fn mean(&self) -> T; + fn mean(&self) -> f64; /// Median of the samples: value separating the lower half of the samples from the higher half. /// Equal to `self.percentile(50.0)`. /// /// See: https://en.wikipedia.org/wiki/Median - fn median(&self) -> T; + fn median(&self) -> f64; /// Variance of the samples: bias-corrected mean of the squares of the differences of each /// sample from the sample mean. Note that this calculates the _sample variance_ rather than the @@ -70,7 +68,7 @@ pub trait Stats { /// than `n`. /// /// See: https://en.wikipedia.org/wiki/Variance - fn var(&self) -> T; + fn var(&self) -> f64; /// Standard deviation: the square root of the sample variance. /// @@ -78,13 +76,13 @@ pub trait Stats { /// `median_abs_dev` for unknown distributions. /// /// See: https://en.wikipedia.org/wiki/Standard_deviation - fn std_dev(&self) -> T; + fn std_dev(&self) -> f64; /// Standard deviation as a percent of the mean value. See `std_dev` and `mean`. /// /// Note: this is not a robust statistic for non-normal distributions. Prefer the /// `median_abs_dev_pct` for unknown distributions. - fn std_dev_pct(&self) -> T; + fn std_dev_pct(&self) -> f64; /// Scaled median of the absolute deviations of each sample from the sample median. This is a /// robust (distribution-agnostic) estimator of sample variability. Use this in preference to @@ -93,10 +91,10 @@ pub trait Stats { /// deviation. /// /// See: http://en.wikipedia.org/wiki/Median_absolute_deviation - fn median_abs_dev(&self) -> T; + fn median_abs_dev(&self) -> f64; /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`. - fn median_abs_dev_pct(&self) -> T; + fn median_abs_dev_pct(&self) -> f64; /// Percentile: the value below which `pct` percent of the values in `self` fall. For example, /// percentile(95.0) will return the value `v` such that 95% of the samples `s` in `self` @@ -105,7 +103,7 @@ pub trait Stats { /// Calculated by linear interpolation between closest ranks. /// /// See: http://en.wikipedia.org/wiki/Percentile - fn percentile(&self, pct: T) -> T; + fn percentile(&self, pct: f64) -> f64; /// Quartiles of the sample: three values that divide the sample into four equal groups, each /// with 1/4 of the data. The middle value is the median. See `median` and `percentile`. This @@ -113,36 +111,36 @@ pub trait Stats { /// is otherwise equivalent. /// /// See also: https://en.wikipedia.org/wiki/Quartile - fn quartiles(&self) -> (T,T,T); + fn quartiles(&self) -> (f64,f64,f64); /// Inter-quartile range: the difference between the 25th percentile (1st quartile) and the 75th /// percentile (3rd quartile). See `quartiles`. /// /// See also: https://en.wikipedia.org/wiki/Interquartile_range - fn iqr(&self) -> T; + fn iqr(&self) -> f64; } /// Extracted collection of all the summary statistics of a sample set. #[derive(Clone, PartialEq)] #[allow(missing_docs)] -pub struct Summary { - pub sum: T, - pub min: T, - pub max: T, - pub mean: T, - pub median: T, - pub var: T, - pub std_dev: T, - pub std_dev_pct: T, - pub median_abs_dev: T, - pub median_abs_dev_pct: T, - pub quartiles: (T,T,T), - pub iqr: T, +pub struct Summary { + pub sum: f64, + pub min: f64, + pub max: f64, + pub mean: f64, + pub median: f64, + pub var: f64, + pub std_dev: f64, + pub std_dev_pct: f64, + pub median_abs_dev: f64, + pub median_abs_dev_pct: f64, + pub quartiles: (f64,f64,f64), + pub iqr: f64, } -impl Summary { +impl Summary { /// Construct a new summary of a sample set. - pub fn new(samples: &[T]) -> Summary { + pub fn new(samples: &[f64]) -> Summary { Summary { sum: samples.sum(), min: samples.min(), @@ -160,9 +158,9 @@ impl Summary { } } -impl Stats for [T] { +impl Stats for [f64] { // FIXME #11059 handle NaN, inf and overflow - fn sum(&self) -> T { + fn sum(&self) -> f64 { let mut partials = vec![]; for &x in self { @@ -171,7 +169,7 @@ impl Stats for [T] { // This inner loop applies `hi`/`lo` summation to each // partial so that the list of partial sums remains exact. for i in 0..partials.len() { - let mut y: T = partials[i]; + let mut y: f64 = partials[i]; if x.abs() < y.abs() { mem::swap(&mut x, &mut y); } @@ -179,7 +177,7 @@ impl Stats for [T] { // `lo`. Together `hi+lo` are exactly equal to `x+y`. let hi = x + y; let lo = y - (hi - x); - if lo != Float::zero() { + if lo != 0.0 { partials[j] = lo; j += 1; } @@ -192,35 +190,35 @@ impl Stats for [T] { partials.truncate(j+1); } } - let zero: T = Float::zero(); + let zero: f64 = 0.0; partials.iter().fold(zero, |p, q| p + *q) } - fn min(&self) -> T { - assert!(self.len() != 0); + fn min(&self) -> f64 { + assert!(!self.is_empty()); self.iter().fold(self[0], |p, q| p.min(*q)) } - fn max(&self) -> T { - assert!(self.len() != 0); + fn max(&self) -> f64 { + assert!(!self.is_empty()); self.iter().fold(self[0], |p, q| p.max(*q)) } - fn mean(&self) -> T { - assert!(self.len() != 0); - self.sum() / FromPrimitive::from_usize(self.len()).unwrap() + fn mean(&self) -> f64 { + assert!(!self.is_empty()); + self.sum() / (self.len() as f64) } - fn median(&self) -> T { - self.percentile(FromPrimitive::from_usize(50).unwrap()) + fn median(&self) -> f64 { + self.percentile(50 as f64) } - fn var(&self) -> T { + fn var(&self) -> f64 { if self.len() < 2 { - Float::zero() + 0.0 } else { let mean = self.mean(); - let mut v: T = Float::zero(); + let mut v: f64 = 0.0; for s in self { let x = *s - mean; v = v + x*x; @@ -228,53 +226,53 @@ impl Stats for [T] { // NB: this is _supposed to be_ len-1, not len. If you // change it back to len, you will be calculating a // population variance, not a sample variance. - let denom = FromPrimitive::from_usize(self.len()-1).unwrap(); + let denom = (self.len() - 1) as f64; v/denom } } - fn std_dev(&self) -> T { + fn std_dev(&self) -> f64 { self.var().sqrt() } - fn std_dev_pct(&self) -> T { - let hundred = FromPrimitive::from_usize(100).unwrap(); + fn std_dev_pct(&self) -> f64 { + let hundred = 100 as f64; (self.std_dev() / self.mean()) * hundred } - fn median_abs_dev(&self) -> T { + fn median_abs_dev(&self) -> f64 { let med = self.median(); - let abs_devs: Vec = self.iter().map(|&v| (med - v).abs()).collect(); + let abs_devs: Vec = self.iter().map(|&v| (med - v).abs()).collect(); // This constant is derived by smarter statistics brains than me, but it is // consistent with how R and other packages treat the MAD. - let number = FromPrimitive::from_f64(1.4826).unwrap(); + let number = 1.4826; abs_devs.median() * number } - fn median_abs_dev_pct(&self) -> T { - let hundred = FromPrimitive::from_usize(100).unwrap(); + fn median_abs_dev_pct(&self) -> f64 { + let hundred = 100 as f64; (self.median_abs_dev() / self.median()) * hundred } - fn percentile(&self, pct: T) -> T { + fn percentile(&self, pct: f64) -> f64 { let mut tmp = self.to_vec(); local_sort(&mut tmp); percentile_of_sorted(&tmp, pct) } - fn quartiles(&self) -> (T,T,T) { + fn quartiles(&self) -> (f64,f64,f64) { let mut tmp = self.to_vec(); local_sort(&mut tmp); - let first = FromPrimitive::from_usize(25).unwrap(); + let first = 25f64; let a = percentile_of_sorted(&tmp, first); - let secound = FromPrimitive::from_usize(50).unwrap(); + let secound = 50f64; let b = percentile_of_sorted(&tmp, secound); - let third = FromPrimitive::from_usize(75).unwrap(); + let third = 75f64; let c = percentile_of_sorted(&tmp, third); (a,b,c) } - fn iqr(&self) -> T { + fn iqr(&self) -> f64 { let (a,_,c) = self.quartiles(); c - a } @@ -283,41 +281,41 @@ impl Stats for [T] { // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using // linear interpolation. If samples are not sorted, return nonsensical value. -fn percentile_of_sorted(sorted_samples: &[T], - pct: T) -> T { - assert!(sorted_samples.len() != 0); +fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { + assert!(!sorted_samples.is_empty()); if sorted_samples.len() == 1 { return sorted_samples[0]; } - let zero: T = Float::zero(); + let zero: f64 = 0.0; assert!(zero <= pct); - let hundred = FromPrimitive::from_usize(100).unwrap(); + let hundred = 100f64; assert!(pct <= hundred); if pct == hundred { return sorted_samples[sorted_samples.len() - 1]; } - let length = FromPrimitive::from_usize(sorted_samples.len() - 1).unwrap(); + let length = (sorted_samples.len() - 1) as f64; let rank = (pct / hundred) * length; let lrank = rank.floor(); let d = rank - lrank; - let n = lrank.to_usize().unwrap(); + let n = lrank as usize; let lo = sorted_samples[n]; let hi = sorted_samples[n+1]; lo + (hi - lo) * d } -/// Winsorize a set of samples, replacing values above the `100-pct` percentile and below the `pct` -/// percentile with those percentiles themselves. This is a way of minimizing the effect of -/// outliers, at the cost of biasing the sample. It differs from trimming in that it does not -/// change the number of samples, just changes the values of those that are outliers. +/// Winsorize a set of samples, replacing values above the `100-pct` percentile +/// and below the `pct` percentile with those percentiles themselves. This is a +/// way of minimizing the effect of outliers, at the cost of biasing the sample. +/// It differs from trimming in that it does not change the number of samples, +/// just changes the values of those that are outliers. /// /// See: http://en.wikipedia.org/wiki/Winsorising -pub fn winsorize(samples: &mut [T], pct: T) { +pub fn winsorize(samples: &mut [f64], pct: f64) { let mut tmp = samples.to_vec(); local_sort(&mut tmp); let lo = percentile_of_sorted(&tmp, pct); - let hundred: T = FromPrimitive::from_usize(100).unwrap(); + let hundred = 100 as f64; let hi = percentile_of_sorted(&tmp, hundred-pct); for samp in samples { if *samp > hi { @@ -334,23 +332,23 @@ pub fn winsorize(samples: &mut [T], pct: T) { mod tests { use stats::Stats; use stats::Summary; - use std::old_io::{self, Writer}; use std::f64; + use std::io::prelude::*; + use std::io; macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ - use std::num::Float; let (a, b) = (&$a, &$b); assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); }) } - fn check(samples: &[f64], summ: &Summary) { + fn check(samples: &[f64], summ: &Summary) { let summ2 = Summary::new(samples); - let mut w = old_io::stdout(); + let mut w = io::sink(); let w = &mut w; (write!(w, "\n")).unwrap(); diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs index 6879fa7b3b..da8eb3686e 100644 --- a/src/libunicode/lib.rs +++ b/src/libunicode/lib.rs @@ -39,9 +39,6 @@ extern crate core; -// regex module -pub use tables::regex; - mod normalize; mod tables; mod u_str; diff --git a/src/libunicode/tables.rs b/src/libunicode/tables.rs index 1fb6ee7bc7..e70ec36638 100644 --- a/src/libunicode/tables.rs +++ b/src/libunicode/tables.rs @@ -27,193 +27,6 @@ fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { } pub mod general_category { - pub const C_table: &'static [(char, char)] = &[ - ('\u{0}', '\u{1f}'), ('\u{7f}', '\u{9f}'), ('\u{ad}', '\u{ad}'), ('\u{378}', '\u{379}'), - ('\u{380}', '\u{383}'), ('\u{38b}', '\u{38b}'), ('\u{38d}', '\u{38d}'), ('\u{3a2}', - '\u{3a2}'), ('\u{530}', '\u{530}'), ('\u{557}', '\u{558}'), ('\u{560}', '\u{560}'), - ('\u{588}', '\u{588}'), ('\u{58b}', '\u{58c}'), ('\u{590}', '\u{590}'), ('\u{5c8}', - '\u{5cf}'), ('\u{5eb}', '\u{5ef}'), ('\u{5f5}', '\u{605}'), ('\u{61c}', '\u{61d}'), - ('\u{6dd}', '\u{6dd}'), ('\u{70e}', '\u{70f}'), ('\u{74b}', '\u{74c}'), ('\u{7b2}', - '\u{7bf}'), ('\u{7fb}', '\u{7ff}'), ('\u{82e}', '\u{82f}'), ('\u{83f}', '\u{83f}'), - ('\u{85c}', '\u{85d}'), ('\u{85f}', '\u{89f}'), ('\u{8b3}', '\u{8e3}'), ('\u{984}', - '\u{984}'), ('\u{98d}', '\u{98e}'), ('\u{991}', '\u{992}'), ('\u{9a9}', '\u{9a9}'), - ('\u{9b1}', '\u{9b1}'), ('\u{9b3}', '\u{9b5}'), ('\u{9ba}', '\u{9bb}'), ('\u{9c5}', - '\u{9c6}'), ('\u{9c9}', '\u{9ca}'), ('\u{9cf}', '\u{9d6}'), ('\u{9d8}', '\u{9db}'), - ('\u{9de}', '\u{9de}'), ('\u{9e4}', '\u{9e5}'), ('\u{9fc}', '\u{a00}'), ('\u{a04}', - '\u{a04}'), ('\u{a0b}', '\u{a0e}'), ('\u{a11}', '\u{a12}'), ('\u{a29}', '\u{a29}'), - ('\u{a31}', '\u{a31}'), ('\u{a34}', '\u{a34}'), ('\u{a37}', '\u{a37}'), ('\u{a3a}', - '\u{a3b}'), ('\u{a3d}', '\u{a3d}'), ('\u{a43}', '\u{a46}'), ('\u{a49}', '\u{a4a}'), - ('\u{a4e}', '\u{a50}'), ('\u{a52}', '\u{a58}'), ('\u{a5d}', '\u{a5d}'), ('\u{a5f}', - '\u{a65}'), ('\u{a76}', '\u{a80}'), ('\u{a84}', '\u{a84}'), ('\u{a8e}', '\u{a8e}'), - ('\u{a92}', '\u{a92}'), ('\u{aa9}', '\u{aa9}'), ('\u{ab1}', '\u{ab1}'), ('\u{ab4}', - '\u{ab4}'), ('\u{aba}', '\u{abb}'), ('\u{ac6}', '\u{ac6}'), ('\u{aca}', '\u{aca}'), - ('\u{ace}', '\u{acf}'), ('\u{ad1}', '\u{adf}'), ('\u{ae4}', '\u{ae5}'), ('\u{af2}', - '\u{b00}'), ('\u{b04}', '\u{b04}'), ('\u{b0d}', '\u{b0e}'), ('\u{b11}', '\u{b12}'), - ('\u{b29}', '\u{b29}'), ('\u{b31}', '\u{b31}'), ('\u{b34}', '\u{b34}'), ('\u{b3a}', - '\u{b3b}'), ('\u{b45}', '\u{b46}'), ('\u{b49}', '\u{b4a}'), ('\u{b4e}', '\u{b55}'), - ('\u{b58}', '\u{b5b}'), ('\u{b5e}', '\u{b5e}'), ('\u{b64}', '\u{b65}'), ('\u{b78}', - '\u{b81}'), ('\u{b84}', '\u{b84}'), ('\u{b8b}', '\u{b8d}'), ('\u{b91}', '\u{b91}'), - ('\u{b96}', '\u{b98}'), ('\u{b9b}', '\u{b9b}'), ('\u{b9d}', '\u{b9d}'), ('\u{ba0}', - '\u{ba2}'), ('\u{ba5}', '\u{ba7}'), ('\u{bab}', '\u{bad}'), ('\u{bba}', '\u{bbd}'), - ('\u{bc3}', '\u{bc5}'), ('\u{bc9}', '\u{bc9}'), ('\u{bce}', '\u{bcf}'), ('\u{bd1}', - '\u{bd6}'), ('\u{bd8}', '\u{be5}'), ('\u{bfb}', '\u{bff}'), ('\u{c04}', '\u{c04}'), - ('\u{c0d}', '\u{c0d}'), ('\u{c11}', '\u{c11}'), ('\u{c29}', '\u{c29}'), ('\u{c3a}', - '\u{c3c}'), ('\u{c45}', '\u{c45}'), ('\u{c49}', '\u{c49}'), ('\u{c4e}', '\u{c54}'), - ('\u{c57}', '\u{c57}'), ('\u{c5a}', '\u{c5f}'), ('\u{c64}', '\u{c65}'), ('\u{c70}', - '\u{c77}'), ('\u{c80}', '\u{c80}'), ('\u{c84}', '\u{c84}'), ('\u{c8d}', '\u{c8d}'), - ('\u{c91}', '\u{c91}'), ('\u{ca9}', '\u{ca9}'), ('\u{cb4}', '\u{cb4}'), ('\u{cba}', - '\u{cbb}'), ('\u{cc5}', '\u{cc5}'), ('\u{cc9}', '\u{cc9}'), ('\u{cce}', '\u{cd4}'), - ('\u{cd7}', '\u{cdd}'), ('\u{cdf}', '\u{cdf}'), ('\u{ce4}', '\u{ce5}'), ('\u{cf0}', - '\u{cf0}'), ('\u{cf3}', '\u{d00}'), ('\u{d04}', '\u{d04}'), ('\u{d0d}', '\u{d0d}'), - ('\u{d11}', '\u{d11}'), ('\u{d3b}', '\u{d3c}'), ('\u{d45}', '\u{d45}'), ('\u{d49}', - '\u{d49}'), ('\u{d4f}', '\u{d56}'), ('\u{d58}', '\u{d5f}'), ('\u{d64}', '\u{d65}'), - ('\u{d76}', '\u{d78}'), ('\u{d80}', '\u{d81}'), ('\u{d84}', '\u{d84}'), ('\u{d97}', - '\u{d99}'), ('\u{db2}', '\u{db2}'), ('\u{dbc}', '\u{dbc}'), ('\u{dbe}', '\u{dbf}'), - ('\u{dc7}', '\u{dc9}'), ('\u{dcb}', '\u{dce}'), ('\u{dd5}', '\u{dd5}'), ('\u{dd7}', - '\u{dd7}'), ('\u{de0}', '\u{de5}'), ('\u{df0}', '\u{df1}'), ('\u{df5}', '\u{e00}'), - ('\u{e3b}', '\u{e3e}'), ('\u{e5c}', '\u{e80}'), ('\u{e83}', '\u{e83}'), ('\u{e85}', - '\u{e86}'), ('\u{e89}', '\u{e89}'), ('\u{e8b}', '\u{e8c}'), ('\u{e8e}', '\u{e93}'), - ('\u{e98}', '\u{e98}'), ('\u{ea0}', '\u{ea0}'), ('\u{ea4}', '\u{ea4}'), ('\u{ea6}', - '\u{ea6}'), ('\u{ea8}', '\u{ea9}'), ('\u{eac}', '\u{eac}'), ('\u{eba}', '\u{eba}'), - ('\u{ebe}', '\u{ebf}'), ('\u{ec5}', '\u{ec5}'), ('\u{ec7}', '\u{ec7}'), ('\u{ece}', - '\u{ecf}'), ('\u{eda}', '\u{edb}'), ('\u{ee0}', '\u{eff}'), ('\u{f48}', '\u{f48}'), - ('\u{f6d}', '\u{f70}'), ('\u{f98}', '\u{f98}'), ('\u{fbd}', '\u{fbd}'), ('\u{fcd}', - '\u{fcd}'), ('\u{fdb}', '\u{fff}'), ('\u{10c6}', '\u{10c6}'), ('\u{10c8}', '\u{10cc}'), - ('\u{10ce}', '\u{10cf}'), ('\u{1249}', '\u{1249}'), ('\u{124e}', '\u{124f}'), ('\u{1257}', - '\u{1257}'), ('\u{1259}', '\u{1259}'), ('\u{125e}', '\u{125f}'), ('\u{1289}', '\u{1289}'), - ('\u{128e}', '\u{128f}'), ('\u{12b1}', '\u{12b1}'), ('\u{12b6}', '\u{12b7}'), ('\u{12bf}', - '\u{12bf}'), ('\u{12c1}', '\u{12c1}'), ('\u{12c6}', '\u{12c7}'), ('\u{12d7}', '\u{12d7}'), - ('\u{1311}', '\u{1311}'), ('\u{1316}', '\u{1317}'), ('\u{135b}', '\u{135c}'), ('\u{137d}', - '\u{137f}'), ('\u{139a}', '\u{139f}'), ('\u{13f5}', '\u{13ff}'), ('\u{169d}', '\u{169f}'), - ('\u{16f9}', '\u{16ff}'), ('\u{170d}', '\u{170d}'), ('\u{1715}', '\u{171f}'), ('\u{1737}', - '\u{173f}'), ('\u{1754}', '\u{175f}'), ('\u{176d}', '\u{176d}'), ('\u{1771}', '\u{1771}'), - ('\u{1774}', '\u{177f}'), ('\u{17de}', '\u{17df}'), ('\u{17ea}', '\u{17ef}'), ('\u{17fa}', - '\u{17ff}'), ('\u{180e}', '\u{180f}'), ('\u{181a}', '\u{181f}'), ('\u{1878}', '\u{187f}'), - ('\u{18ab}', '\u{18af}'), ('\u{18f6}', '\u{18ff}'), ('\u{191f}', '\u{191f}'), ('\u{192c}', - '\u{192f}'), ('\u{193c}', '\u{193f}'), ('\u{1941}', '\u{1943}'), ('\u{196e}', '\u{196f}'), - ('\u{1975}', '\u{197f}'), ('\u{19ac}', '\u{19af}'), ('\u{19ca}', '\u{19cf}'), ('\u{19db}', - '\u{19dd}'), ('\u{1a1c}', '\u{1a1d}'), ('\u{1a5f}', '\u{1a5f}'), ('\u{1a7d}', '\u{1a7e}'), - ('\u{1a8a}', '\u{1a8f}'), ('\u{1a9a}', '\u{1a9f}'), ('\u{1aae}', '\u{1aaf}'), ('\u{1abf}', - '\u{1aff}'), ('\u{1b4c}', '\u{1b4f}'), ('\u{1b7d}', '\u{1b7f}'), ('\u{1bf4}', '\u{1bfb}'), - ('\u{1c38}', '\u{1c3a}'), ('\u{1c4a}', '\u{1c4c}'), ('\u{1c80}', '\u{1cbf}'), ('\u{1cc8}', - '\u{1ccf}'), ('\u{1cf7}', '\u{1cf7}'), ('\u{1cfa}', '\u{1cff}'), ('\u{1df6}', '\u{1dfb}'), - ('\u{1f16}', '\u{1f17}'), ('\u{1f1e}', '\u{1f1f}'), ('\u{1f46}', '\u{1f47}'), ('\u{1f4e}', - '\u{1f4f}'), ('\u{1f58}', '\u{1f58}'), ('\u{1f5a}', '\u{1f5a}'), ('\u{1f5c}', '\u{1f5c}'), - ('\u{1f5e}', '\u{1f5e}'), ('\u{1f7e}', '\u{1f7f}'), ('\u{1fb5}', '\u{1fb5}'), ('\u{1fc5}', - '\u{1fc5}'), ('\u{1fd4}', '\u{1fd5}'), ('\u{1fdc}', '\u{1fdc}'), ('\u{1ff0}', '\u{1ff1}'), - ('\u{1ff5}', '\u{1ff5}'), ('\u{1fff}', '\u{1fff}'), ('\u{200b}', '\u{200f}'), ('\u{202a}', - '\u{202e}'), ('\u{2060}', '\u{206f}'), ('\u{2072}', '\u{2073}'), ('\u{208f}', '\u{208f}'), - ('\u{209d}', '\u{209f}'), ('\u{20be}', '\u{20cf}'), ('\u{20f1}', '\u{20ff}'), ('\u{218a}', - '\u{218f}'), ('\u{23fb}', '\u{23ff}'), ('\u{2427}', '\u{243f}'), ('\u{244b}', '\u{245f}'), - ('\u{2b74}', '\u{2b75}'), ('\u{2b96}', '\u{2b97}'), ('\u{2bba}', '\u{2bbc}'), ('\u{2bc9}', - '\u{2bc9}'), ('\u{2bd2}', '\u{2bff}'), ('\u{2c2f}', '\u{2c2f}'), ('\u{2c5f}', '\u{2c5f}'), - ('\u{2cf4}', '\u{2cf8}'), ('\u{2d26}', '\u{2d26}'), ('\u{2d28}', '\u{2d2c}'), ('\u{2d2e}', - '\u{2d2f}'), ('\u{2d68}', '\u{2d6e}'), ('\u{2d71}', '\u{2d7e}'), ('\u{2d97}', '\u{2d9f}'), - ('\u{2da7}', '\u{2da7}'), ('\u{2daf}', '\u{2daf}'), ('\u{2db7}', '\u{2db7}'), ('\u{2dbf}', - '\u{2dbf}'), ('\u{2dc7}', '\u{2dc7}'), ('\u{2dcf}', '\u{2dcf}'), ('\u{2dd7}', '\u{2dd7}'), - ('\u{2ddf}', '\u{2ddf}'), ('\u{2e43}', '\u{2e7f}'), ('\u{2e9a}', '\u{2e9a}'), ('\u{2ef4}', - '\u{2eff}'), ('\u{2fd6}', '\u{2fef}'), ('\u{2ffc}', '\u{2fff}'), ('\u{3040}', '\u{3040}'), - ('\u{3097}', '\u{3098}'), ('\u{3100}', '\u{3104}'), ('\u{312e}', '\u{3130}'), ('\u{318f}', - '\u{318f}'), ('\u{31bb}', '\u{31bf}'), ('\u{31e4}', '\u{31ef}'), ('\u{321f}', '\u{321f}'), - ('\u{32ff}', '\u{32ff}'), ('\u{4db6}', '\u{4dbf}'), ('\u{9fcd}', '\u{9fff}'), ('\u{a48d}', - '\u{a48f}'), ('\u{a4c7}', '\u{a4cf}'), ('\u{a62c}', '\u{a63f}'), ('\u{a69e}', '\u{a69e}'), - ('\u{a6f8}', '\u{a6ff}'), ('\u{a78f}', '\u{a78f}'), ('\u{a7ae}', '\u{a7af}'), ('\u{a7b2}', - '\u{a7f6}'), ('\u{a82c}', '\u{a82f}'), ('\u{a83a}', '\u{a83f}'), ('\u{a878}', '\u{a87f}'), - ('\u{a8c5}', '\u{a8cd}'), ('\u{a8da}', '\u{a8df}'), ('\u{a8fc}', '\u{a8ff}'), ('\u{a954}', - '\u{a95e}'), ('\u{a97d}', '\u{a97f}'), ('\u{a9ce}', '\u{a9ce}'), ('\u{a9da}', '\u{a9dd}'), - ('\u{a9ff}', '\u{a9ff}'), ('\u{aa37}', '\u{aa3f}'), ('\u{aa4e}', '\u{aa4f}'), ('\u{aa5a}', - '\u{aa5b}'), ('\u{aac3}', '\u{aada}'), ('\u{aaf7}', '\u{ab00}'), ('\u{ab07}', '\u{ab08}'), - ('\u{ab0f}', '\u{ab10}'), ('\u{ab17}', '\u{ab1f}'), ('\u{ab27}', '\u{ab27}'), ('\u{ab2f}', - '\u{ab2f}'), ('\u{ab60}', '\u{ab63}'), ('\u{ab66}', '\u{abbf}'), ('\u{abee}', '\u{abef}'), - ('\u{abfa}', '\u{abff}'), ('\u{d7a4}', '\u{d7af}'), ('\u{d7c7}', '\u{d7ca}'), ('\u{d7fc}', - '\u{d7ff}'), ('\u{e000}', '\u{f8ff}'), ('\u{fa6e}', '\u{fa6f}'), ('\u{fada}', '\u{faff}'), - ('\u{fb07}', '\u{fb12}'), ('\u{fb18}', '\u{fb1c}'), ('\u{fb37}', '\u{fb37}'), ('\u{fb3d}', - '\u{fb3d}'), ('\u{fb3f}', '\u{fb3f}'), ('\u{fb42}', '\u{fb42}'), ('\u{fb45}', '\u{fb45}'), - ('\u{fbc2}', '\u{fbd2}'), ('\u{fd40}', '\u{fd4f}'), ('\u{fd90}', '\u{fd91}'), ('\u{fdc8}', - '\u{fdef}'), ('\u{fdfe}', '\u{fdff}'), ('\u{fe1a}', '\u{fe1f}'), ('\u{fe2e}', '\u{fe2f}'), - ('\u{fe53}', '\u{fe53}'), ('\u{fe67}', '\u{fe67}'), ('\u{fe6c}', '\u{fe6f}'), ('\u{fe75}', - '\u{fe75}'), ('\u{fefd}', '\u{ff00}'), ('\u{ffbf}', '\u{ffc1}'), ('\u{ffc8}', '\u{ffc9}'), - ('\u{ffd0}', '\u{ffd1}'), ('\u{ffd8}', '\u{ffd9}'), ('\u{ffdd}', '\u{ffdf}'), ('\u{ffe7}', - '\u{ffe7}'), ('\u{ffef}', '\u{fffb}'), ('\u{fffe}', '\u{ffff}'), ('\u{1000c}', '\u{1000c}'), - ('\u{10027}', '\u{10027}'), ('\u{1003b}', '\u{1003b}'), ('\u{1003e}', '\u{1003e}'), - ('\u{1004e}', '\u{1004f}'), ('\u{1005e}', '\u{1007f}'), ('\u{100fb}', '\u{100ff}'), - ('\u{10103}', '\u{10106}'), ('\u{10134}', '\u{10136}'), ('\u{1018d}', '\u{1018f}'), - ('\u{1019c}', '\u{1019f}'), ('\u{101a1}', '\u{101cf}'), ('\u{101fe}', '\u{1027f}'), - ('\u{1029d}', '\u{1029f}'), ('\u{102d1}', '\u{102df}'), ('\u{102fc}', '\u{102ff}'), - ('\u{10324}', '\u{1032f}'), ('\u{1034b}', '\u{1034f}'), ('\u{1037b}', '\u{1037f}'), - ('\u{1039e}', '\u{1039e}'), ('\u{103c4}', '\u{103c7}'), ('\u{103d6}', '\u{103ff}'), - ('\u{1049e}', '\u{1049f}'), ('\u{104aa}', '\u{104ff}'), ('\u{10528}', '\u{1052f}'), - ('\u{10564}', '\u{1056e}'), ('\u{10570}', '\u{105ff}'), ('\u{10737}', '\u{1073f}'), - ('\u{10756}', '\u{1075f}'), ('\u{10768}', '\u{107ff}'), ('\u{10806}', '\u{10807}'), - ('\u{10809}', '\u{10809}'), ('\u{10836}', '\u{10836}'), ('\u{10839}', '\u{1083b}'), - ('\u{1083d}', '\u{1083e}'), ('\u{10856}', '\u{10856}'), ('\u{1089f}', '\u{108a6}'), - ('\u{108b0}', '\u{108ff}'), ('\u{1091c}', '\u{1091e}'), ('\u{1093a}', '\u{1093e}'), - ('\u{10940}', '\u{1097f}'), ('\u{109b8}', '\u{109bd}'), ('\u{109c0}', '\u{109ff}'), - ('\u{10a04}', '\u{10a04}'), ('\u{10a07}', '\u{10a0b}'), ('\u{10a14}', '\u{10a14}'), - ('\u{10a18}', '\u{10a18}'), ('\u{10a34}', '\u{10a37}'), ('\u{10a3b}', '\u{10a3e}'), - ('\u{10a48}', '\u{10a4f}'), ('\u{10a59}', '\u{10a5f}'), ('\u{10aa0}', '\u{10abf}'), - ('\u{10ae7}', '\u{10aea}'), ('\u{10af7}', '\u{10aff}'), ('\u{10b36}', '\u{10b38}'), - ('\u{10b56}', '\u{10b57}'), ('\u{10b73}', '\u{10b77}'), ('\u{10b92}', '\u{10b98}'), - ('\u{10b9d}', '\u{10ba8}'), ('\u{10bb0}', '\u{10bff}'), ('\u{10c49}', '\u{10e5f}'), - ('\u{10e7f}', '\u{10fff}'), ('\u{1104e}', '\u{11051}'), ('\u{11070}', '\u{1107e}'), - ('\u{110bd}', '\u{110bd}'), ('\u{110c2}', '\u{110cf}'), ('\u{110e9}', '\u{110ef}'), - ('\u{110fa}', '\u{110ff}'), ('\u{11135}', '\u{11135}'), ('\u{11144}', '\u{1114f}'), - ('\u{11177}', '\u{1117f}'), ('\u{111c9}', '\u{111cc}'), ('\u{111ce}', '\u{111cf}'), - ('\u{111db}', '\u{111e0}'), ('\u{111f5}', '\u{111ff}'), ('\u{11212}', '\u{11212}'), - ('\u{1123e}', '\u{112af}'), ('\u{112eb}', '\u{112ef}'), ('\u{112fa}', '\u{11300}'), - ('\u{11304}', '\u{11304}'), ('\u{1130d}', '\u{1130e}'), ('\u{11311}', '\u{11312}'), - ('\u{11329}', '\u{11329}'), ('\u{11331}', '\u{11331}'), ('\u{11334}', '\u{11334}'), - ('\u{1133a}', '\u{1133b}'), ('\u{11345}', '\u{11346}'), ('\u{11349}', '\u{1134a}'), - ('\u{1134e}', '\u{11356}'), ('\u{11358}', '\u{1135c}'), ('\u{11364}', '\u{11365}'), - ('\u{1136d}', '\u{1136f}'), ('\u{11375}', '\u{1147f}'), ('\u{114c8}', '\u{114cf}'), - ('\u{114da}', '\u{1157f}'), ('\u{115b6}', '\u{115b7}'), ('\u{115ca}', '\u{115ff}'), - ('\u{11645}', '\u{1164f}'), ('\u{1165a}', '\u{1167f}'), ('\u{116b8}', '\u{116bf}'), - ('\u{116ca}', '\u{1189f}'), ('\u{118f3}', '\u{118fe}'), ('\u{11900}', '\u{11abf}'), - ('\u{11af9}', '\u{11fff}'), ('\u{12399}', '\u{123ff}'), ('\u{1246f}', '\u{1246f}'), - ('\u{12475}', '\u{12fff}'), ('\u{1342f}', '\u{167ff}'), ('\u{16a39}', '\u{16a3f}'), - ('\u{16a5f}', '\u{16a5f}'), ('\u{16a6a}', '\u{16a6d}'), ('\u{16a70}', '\u{16acf}'), - ('\u{16aee}', '\u{16aef}'), ('\u{16af6}', '\u{16aff}'), ('\u{16b46}', '\u{16b4f}'), - ('\u{16b5a}', '\u{16b5a}'), ('\u{16b62}', '\u{16b62}'), ('\u{16b78}', '\u{16b7c}'), - ('\u{16b90}', '\u{16eff}'), ('\u{16f45}', '\u{16f4f}'), ('\u{16f7f}', '\u{16f8e}'), - ('\u{16fa0}', '\u{1afff}'), ('\u{1b002}', '\u{1bbff}'), ('\u{1bc6b}', '\u{1bc6f}'), - ('\u{1bc7d}', '\u{1bc7f}'), ('\u{1bc89}', '\u{1bc8f}'), ('\u{1bc9a}', '\u{1bc9b}'), - ('\u{1bca0}', '\u{1cfff}'), ('\u{1d0f6}', '\u{1d0ff}'), ('\u{1d127}', '\u{1d128}'), - ('\u{1d173}', '\u{1d17a}'), ('\u{1d1de}', '\u{1d1ff}'), ('\u{1d246}', '\u{1d2ff}'), - ('\u{1d357}', '\u{1d35f}'), ('\u{1d372}', '\u{1d3ff}'), ('\u{1d455}', '\u{1d455}'), - ('\u{1d49d}', '\u{1d49d}'), ('\u{1d4a0}', '\u{1d4a1}'), ('\u{1d4a3}', '\u{1d4a4}'), - ('\u{1d4a7}', '\u{1d4a8}'), ('\u{1d4ad}', '\u{1d4ad}'), ('\u{1d4ba}', '\u{1d4ba}'), - ('\u{1d4bc}', '\u{1d4bc}'), ('\u{1d4c4}', '\u{1d4c4}'), ('\u{1d506}', '\u{1d506}'), - ('\u{1d50b}', '\u{1d50c}'), ('\u{1d515}', '\u{1d515}'), ('\u{1d51d}', '\u{1d51d}'), - ('\u{1d53a}', '\u{1d53a}'), ('\u{1d53f}', '\u{1d53f}'), ('\u{1d545}', '\u{1d545}'), - ('\u{1d547}', '\u{1d549}'), ('\u{1d551}', '\u{1d551}'), ('\u{1d6a6}', '\u{1d6a7}'), - ('\u{1d7cc}', '\u{1d7cd}'), ('\u{1d800}', '\u{1e7ff}'), ('\u{1e8c5}', '\u{1e8c6}'), - ('\u{1e8d7}', '\u{1edff}'), ('\u{1ee04}', '\u{1ee04}'), ('\u{1ee20}', '\u{1ee20}'), - ('\u{1ee23}', '\u{1ee23}'), ('\u{1ee25}', '\u{1ee26}'), ('\u{1ee28}', '\u{1ee28}'), - ('\u{1ee33}', '\u{1ee33}'), ('\u{1ee38}', '\u{1ee38}'), ('\u{1ee3a}', '\u{1ee3a}'), - ('\u{1ee3c}', '\u{1ee41}'), ('\u{1ee43}', '\u{1ee46}'), ('\u{1ee48}', '\u{1ee48}'), - ('\u{1ee4a}', '\u{1ee4a}'), ('\u{1ee4c}', '\u{1ee4c}'), ('\u{1ee50}', '\u{1ee50}'), - ('\u{1ee53}', '\u{1ee53}'), ('\u{1ee55}', '\u{1ee56}'), ('\u{1ee58}', '\u{1ee58}'), - ('\u{1ee5a}', '\u{1ee5a}'), ('\u{1ee5c}', '\u{1ee5c}'), ('\u{1ee5e}', '\u{1ee5e}'), - ('\u{1ee60}', '\u{1ee60}'), ('\u{1ee63}', '\u{1ee63}'), ('\u{1ee65}', '\u{1ee66}'), - ('\u{1ee6b}', '\u{1ee6b}'), ('\u{1ee73}', '\u{1ee73}'), ('\u{1ee78}', '\u{1ee78}'), - ('\u{1ee7d}', '\u{1ee7d}'), ('\u{1ee7f}', '\u{1ee7f}'), ('\u{1ee8a}', '\u{1ee8a}'), - ('\u{1ee9c}', '\u{1eea0}'), ('\u{1eea4}', '\u{1eea4}'), ('\u{1eeaa}', '\u{1eeaa}'), - ('\u{1eebc}', '\u{1eeef}'), ('\u{1eef2}', '\u{1efff}'), ('\u{1f02c}', '\u{1f02f}'), - ('\u{1f094}', '\u{1f09f}'), ('\u{1f0af}', '\u{1f0b0}'), ('\u{1f0c0}', '\u{1f0c0}'), - ('\u{1f0d0}', '\u{1f0d0}'), ('\u{1f0f6}', '\u{1f0ff}'), ('\u{1f10d}', '\u{1f10f}'), - ('\u{1f12f}', '\u{1f12f}'), ('\u{1f16c}', '\u{1f16f}'), ('\u{1f19b}', '\u{1f1e5}'), - ('\u{1f203}', '\u{1f20f}'), ('\u{1f23b}', '\u{1f23f}'), ('\u{1f249}', '\u{1f24f}'), - ('\u{1f252}', '\u{1f2ff}'), ('\u{1f32d}', '\u{1f32f}'), ('\u{1f37e}', '\u{1f37f}'), - ('\u{1f3cf}', '\u{1f3d3}'), ('\u{1f3f8}', '\u{1f3ff}'), ('\u{1f4ff}', '\u{1f4ff}'), - ('\u{1f54b}', '\u{1f54f}'), ('\u{1f57a}', '\u{1f57a}'), ('\u{1f5a4}', '\u{1f5a4}'), - ('\u{1f643}', '\u{1f644}'), ('\u{1f6d0}', '\u{1f6df}'), ('\u{1f6ed}', '\u{1f6ef}'), - ('\u{1f6f4}', '\u{1f6ff}'), ('\u{1f774}', '\u{1f77f}'), ('\u{1f7d5}', '\u{1f7ff}'), - ('\u{1f80c}', '\u{1f80f}'), ('\u{1f848}', '\u{1f84f}'), ('\u{1f85a}', '\u{1f85f}'), - ('\u{1f888}', '\u{1f88f}'), ('\u{1f8ae}', '\u{1ffff}'), ('\u{2a6d7}', '\u{2a6ff}'), - ('\u{2b735}', '\u{2b73f}'), ('\u{2b81e}', '\u{2f7ff}'), ('\u{2fa1e}', '\u{e00ff}'), - ('\u{e01f0}', '\u{10ffff}') - ]; - pub const Cc_table: &'static [(char, char)] = &[ ('\u{0}', '\u{1f}'), ('\u{7f}', '\u{9f}') ]; @@ -222,1130 +35,6 @@ pub mod general_category { super::bsearch_range_table(c, Cc_table) } - pub const Cf_table: &'static [(char, char)] = &[ - ('\u{ad}', '\u{ad}'), ('\u{600}', '\u{605}'), ('\u{61c}', '\u{61c}'), ('\u{6dd}', - '\u{6dd}'), ('\u{70f}', '\u{70f}'), ('\u{180e}', '\u{180e}'), ('\u{200b}', '\u{200f}'), - ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), ('\u{2066}', '\u{206f}'), ('\u{feff}', - '\u{feff}'), ('\u{fff9}', '\u{fffb}'), ('\u{110bd}', '\u{110bd}'), ('\u{1bca0}', - '\u{1bca3}'), ('\u{1d173}', '\u{1d17a}'), ('\u{e0001}', '\u{e0001}'), ('\u{e0020}', - '\u{e007f}') - ]; - - pub const Cn_table: &'static [(char, char)] = &[ - ('\u{378}', '\u{379}'), ('\u{380}', '\u{383}'), ('\u{38b}', '\u{38b}'), ('\u{38d}', - '\u{38d}'), ('\u{3a2}', '\u{3a2}'), ('\u{530}', '\u{530}'), ('\u{557}', '\u{558}'), - ('\u{560}', '\u{560}'), ('\u{588}', '\u{588}'), ('\u{58b}', '\u{58c}'), ('\u{590}', - '\u{590}'), ('\u{5c8}', '\u{5cf}'), ('\u{5eb}', '\u{5ef}'), ('\u{5f5}', '\u{5ff}'), - ('\u{61d}', '\u{61d}'), ('\u{70e}', '\u{70e}'), ('\u{74b}', '\u{74c}'), ('\u{7b2}', - '\u{7bf}'), ('\u{7fb}', '\u{7ff}'), ('\u{82e}', '\u{82f}'), ('\u{83f}', '\u{83f}'), - ('\u{85c}', '\u{85d}'), ('\u{85f}', '\u{89f}'), ('\u{8b3}', '\u{8e3}'), ('\u{984}', - '\u{984}'), ('\u{98d}', '\u{98e}'), ('\u{991}', '\u{992}'), ('\u{9a9}', '\u{9a9}'), - ('\u{9b1}', '\u{9b1}'), ('\u{9b3}', '\u{9b5}'), ('\u{9ba}', '\u{9bb}'), ('\u{9c5}', - '\u{9c6}'), ('\u{9c9}', '\u{9ca}'), ('\u{9cf}', '\u{9d6}'), ('\u{9d8}', '\u{9db}'), - ('\u{9de}', '\u{9de}'), ('\u{9e4}', '\u{9e5}'), ('\u{9fc}', '\u{a00}'), ('\u{a04}', - '\u{a04}'), ('\u{a0b}', '\u{a0e}'), ('\u{a11}', '\u{a12}'), ('\u{a29}', '\u{a29}'), - ('\u{a31}', '\u{a31}'), ('\u{a34}', '\u{a34}'), ('\u{a37}', '\u{a37}'), ('\u{a3a}', - '\u{a3b}'), ('\u{a3d}', '\u{a3d}'), ('\u{a43}', '\u{a46}'), ('\u{a49}', '\u{a4a}'), - ('\u{a4e}', '\u{a50}'), ('\u{a52}', '\u{a58}'), ('\u{a5d}', '\u{a5d}'), ('\u{a5f}', - '\u{a65}'), ('\u{a76}', '\u{a80}'), ('\u{a84}', '\u{a84}'), ('\u{a8e}', '\u{a8e}'), - ('\u{a92}', '\u{a92}'), ('\u{aa9}', '\u{aa9}'), ('\u{ab1}', '\u{ab1}'), ('\u{ab4}', - '\u{ab4}'), ('\u{aba}', '\u{abb}'), ('\u{ac6}', '\u{ac6}'), ('\u{aca}', '\u{aca}'), - ('\u{ace}', '\u{acf}'), ('\u{ad1}', '\u{adf}'), ('\u{ae4}', '\u{ae5}'), ('\u{af2}', - '\u{b00}'), ('\u{b04}', '\u{b04}'), ('\u{b0d}', '\u{b0e}'), ('\u{b11}', '\u{b12}'), - ('\u{b29}', '\u{b29}'), ('\u{b31}', '\u{b31}'), ('\u{b34}', '\u{b34}'), ('\u{b3a}', - '\u{b3b}'), ('\u{b45}', '\u{b46}'), ('\u{b49}', '\u{b4a}'), ('\u{b4e}', '\u{b55}'), - ('\u{b58}', '\u{b5b}'), ('\u{b5e}', '\u{b5e}'), ('\u{b64}', '\u{b65}'), ('\u{b78}', - '\u{b81}'), ('\u{b84}', '\u{b84}'), ('\u{b8b}', '\u{b8d}'), ('\u{b91}', '\u{b91}'), - ('\u{b96}', '\u{b98}'), ('\u{b9b}', '\u{b9b}'), ('\u{b9d}', '\u{b9d}'), ('\u{ba0}', - '\u{ba2}'), ('\u{ba5}', '\u{ba7}'), ('\u{bab}', '\u{bad}'), ('\u{bba}', '\u{bbd}'), - ('\u{bc3}', '\u{bc5}'), ('\u{bc9}', '\u{bc9}'), ('\u{bce}', '\u{bcf}'), ('\u{bd1}', - '\u{bd6}'), ('\u{bd8}', '\u{be5}'), ('\u{bfb}', '\u{bff}'), ('\u{c04}', '\u{c04}'), - ('\u{c0d}', '\u{c0d}'), ('\u{c11}', '\u{c11}'), ('\u{c29}', '\u{c29}'), ('\u{c3a}', - '\u{c3c}'), ('\u{c45}', '\u{c45}'), ('\u{c49}', '\u{c49}'), ('\u{c4e}', '\u{c54}'), - ('\u{c57}', '\u{c57}'), ('\u{c5a}', '\u{c5f}'), ('\u{c64}', '\u{c65}'), ('\u{c70}', - '\u{c77}'), ('\u{c80}', '\u{c80}'), ('\u{c84}', '\u{c84}'), ('\u{c8d}', '\u{c8d}'), - ('\u{c91}', '\u{c91}'), ('\u{ca9}', '\u{ca9}'), ('\u{cb4}', '\u{cb4}'), ('\u{cba}', - '\u{cbb}'), ('\u{cc5}', '\u{cc5}'), ('\u{cc9}', '\u{cc9}'), ('\u{cce}', '\u{cd4}'), - ('\u{cd7}', '\u{cdd}'), ('\u{cdf}', '\u{cdf}'), ('\u{ce4}', '\u{ce5}'), ('\u{cf0}', - '\u{cf0}'), ('\u{cf3}', '\u{d00}'), ('\u{d04}', '\u{d04}'), ('\u{d0d}', '\u{d0d}'), - ('\u{d11}', '\u{d11}'), ('\u{d3b}', '\u{d3c}'), ('\u{d45}', '\u{d45}'), ('\u{d49}', - '\u{d49}'), ('\u{d4f}', '\u{d56}'), ('\u{d58}', '\u{d5f}'), ('\u{d64}', '\u{d65}'), - ('\u{d76}', '\u{d78}'), ('\u{d80}', '\u{d81}'), ('\u{d84}', '\u{d84}'), ('\u{d97}', - '\u{d99}'), ('\u{db2}', '\u{db2}'), ('\u{dbc}', '\u{dbc}'), ('\u{dbe}', '\u{dbf}'), - ('\u{dc7}', '\u{dc9}'), ('\u{dcb}', '\u{dce}'), ('\u{dd5}', '\u{dd5}'), ('\u{dd7}', - '\u{dd7}'), ('\u{de0}', '\u{de5}'), ('\u{df0}', '\u{df1}'), ('\u{df5}', '\u{e00}'), - ('\u{e3b}', '\u{e3e}'), ('\u{e5c}', '\u{e80}'), ('\u{e83}', '\u{e83}'), ('\u{e85}', - '\u{e86}'), ('\u{e89}', '\u{e89}'), ('\u{e8b}', '\u{e8c}'), ('\u{e8e}', '\u{e93}'), - ('\u{e98}', '\u{e98}'), ('\u{ea0}', '\u{ea0}'), ('\u{ea4}', '\u{ea4}'), ('\u{ea6}', - '\u{ea6}'), ('\u{ea8}', '\u{ea9}'), ('\u{eac}', '\u{eac}'), ('\u{eba}', '\u{eba}'), - ('\u{ebe}', '\u{ebf}'), ('\u{ec5}', '\u{ec5}'), ('\u{ec7}', '\u{ec7}'), ('\u{ece}', - '\u{ecf}'), ('\u{eda}', '\u{edb}'), ('\u{ee0}', '\u{eff}'), ('\u{f48}', '\u{f48}'), - ('\u{f6d}', '\u{f70}'), ('\u{f98}', '\u{f98}'), ('\u{fbd}', '\u{fbd}'), ('\u{fcd}', - '\u{fcd}'), ('\u{fdb}', '\u{fff}'), ('\u{10c6}', '\u{10c6}'), ('\u{10c8}', '\u{10cc}'), - ('\u{10ce}', '\u{10cf}'), ('\u{1249}', '\u{1249}'), ('\u{124e}', '\u{124f}'), ('\u{1257}', - '\u{1257}'), ('\u{1259}', '\u{1259}'), ('\u{125e}', '\u{125f}'), ('\u{1289}', '\u{1289}'), - ('\u{128e}', '\u{128f}'), ('\u{12b1}', '\u{12b1}'), ('\u{12b6}', '\u{12b7}'), ('\u{12bf}', - '\u{12bf}'), ('\u{12c1}', '\u{12c1}'), ('\u{12c6}', '\u{12c7}'), ('\u{12d7}', '\u{12d7}'), - ('\u{1311}', '\u{1311}'), ('\u{1316}', '\u{1317}'), ('\u{135b}', '\u{135c}'), ('\u{137d}', - '\u{137f}'), ('\u{139a}', '\u{139f}'), ('\u{13f5}', '\u{13ff}'), ('\u{169d}', '\u{169f}'), - ('\u{16f9}', '\u{16ff}'), ('\u{170d}', '\u{170d}'), ('\u{1715}', '\u{171f}'), ('\u{1737}', - '\u{173f}'), ('\u{1754}', '\u{175f}'), ('\u{176d}', '\u{176d}'), ('\u{1771}', '\u{1771}'), - ('\u{1774}', '\u{177f}'), ('\u{17de}', '\u{17df}'), ('\u{17ea}', '\u{17ef}'), ('\u{17fa}', - '\u{17ff}'), ('\u{180f}', '\u{180f}'), ('\u{181a}', '\u{181f}'), ('\u{1878}', '\u{187f}'), - ('\u{18ab}', '\u{18af}'), ('\u{18f6}', '\u{18ff}'), ('\u{191f}', '\u{191f}'), ('\u{192c}', - '\u{192f}'), ('\u{193c}', '\u{193f}'), ('\u{1941}', '\u{1943}'), ('\u{196e}', '\u{196f}'), - ('\u{1975}', '\u{197f}'), ('\u{19ac}', '\u{19af}'), ('\u{19ca}', '\u{19cf}'), ('\u{19db}', - '\u{19dd}'), ('\u{1a1c}', '\u{1a1d}'), ('\u{1a5f}', '\u{1a5f}'), ('\u{1a7d}', '\u{1a7e}'), - ('\u{1a8a}', '\u{1a8f}'), ('\u{1a9a}', '\u{1a9f}'), ('\u{1aae}', '\u{1aaf}'), ('\u{1abf}', - '\u{1aff}'), ('\u{1b4c}', '\u{1b4f}'), ('\u{1b7d}', '\u{1b7f}'), ('\u{1bf4}', '\u{1bfb}'), - ('\u{1c38}', '\u{1c3a}'), ('\u{1c4a}', '\u{1c4c}'), ('\u{1c80}', '\u{1cbf}'), ('\u{1cc8}', - '\u{1ccf}'), ('\u{1cf7}', '\u{1cf7}'), ('\u{1cfa}', '\u{1cff}'), ('\u{1df6}', '\u{1dfb}'), - ('\u{1f16}', '\u{1f17}'), ('\u{1f1e}', '\u{1f1f}'), ('\u{1f46}', '\u{1f47}'), ('\u{1f4e}', - '\u{1f4f}'), ('\u{1f58}', '\u{1f58}'), ('\u{1f5a}', '\u{1f5a}'), ('\u{1f5c}', '\u{1f5c}'), - ('\u{1f5e}', '\u{1f5e}'), ('\u{1f7e}', '\u{1f7f}'), ('\u{1fb5}', '\u{1fb5}'), ('\u{1fc5}', - '\u{1fc5}'), ('\u{1fd4}', '\u{1fd5}'), ('\u{1fdc}', '\u{1fdc}'), ('\u{1ff0}', '\u{1ff1}'), - ('\u{1ff5}', '\u{1ff5}'), ('\u{1fff}', '\u{1fff}'), ('\u{2065}', '\u{2065}'), ('\u{2072}', - '\u{2073}'), ('\u{208f}', '\u{208f}'), ('\u{209d}', '\u{209f}'), ('\u{20be}', '\u{20cf}'), - ('\u{20f1}', '\u{20ff}'), ('\u{218a}', '\u{218f}'), ('\u{23fb}', '\u{23ff}'), ('\u{2427}', - '\u{243f}'), ('\u{244b}', '\u{245f}'), ('\u{2b74}', '\u{2b75}'), ('\u{2b96}', '\u{2b97}'), - ('\u{2bba}', '\u{2bbc}'), ('\u{2bc9}', '\u{2bc9}'), ('\u{2bd2}', '\u{2bff}'), ('\u{2c2f}', - '\u{2c2f}'), ('\u{2c5f}', '\u{2c5f}'), ('\u{2cf4}', '\u{2cf8}'), ('\u{2d26}', '\u{2d26}'), - ('\u{2d28}', '\u{2d2c}'), ('\u{2d2e}', '\u{2d2f}'), ('\u{2d68}', '\u{2d6e}'), ('\u{2d71}', - '\u{2d7e}'), ('\u{2d97}', '\u{2d9f}'), ('\u{2da7}', '\u{2da7}'), ('\u{2daf}', '\u{2daf}'), - ('\u{2db7}', '\u{2db7}'), ('\u{2dbf}', '\u{2dbf}'), ('\u{2dc7}', '\u{2dc7}'), ('\u{2dcf}', - '\u{2dcf}'), ('\u{2dd7}', '\u{2dd7}'), ('\u{2ddf}', '\u{2ddf}'), ('\u{2e43}', '\u{2e7f}'), - ('\u{2e9a}', '\u{2e9a}'), ('\u{2ef4}', '\u{2eff}'), ('\u{2fd6}', '\u{2fef}'), ('\u{2ffc}', - '\u{2fff}'), ('\u{3040}', '\u{3040}'), ('\u{3097}', '\u{3098}'), ('\u{3100}', '\u{3104}'), - ('\u{312e}', '\u{3130}'), ('\u{318f}', '\u{318f}'), ('\u{31bb}', '\u{31bf}'), ('\u{31e4}', - '\u{31ef}'), ('\u{321f}', '\u{321f}'), ('\u{32ff}', '\u{32ff}'), ('\u{4db6}', '\u{4dbf}'), - ('\u{9fcd}', '\u{9fff}'), ('\u{a48d}', '\u{a48f}'), ('\u{a4c7}', '\u{a4cf}'), ('\u{a62c}', - '\u{a63f}'), ('\u{a69e}', '\u{a69e}'), ('\u{a6f8}', '\u{a6ff}'), ('\u{a78f}', '\u{a78f}'), - ('\u{a7ae}', '\u{a7af}'), ('\u{a7b2}', '\u{a7f6}'), ('\u{a82c}', '\u{a82f}'), ('\u{a83a}', - '\u{a83f}'), ('\u{a878}', '\u{a87f}'), ('\u{a8c5}', '\u{a8cd}'), ('\u{a8da}', '\u{a8df}'), - ('\u{a8fc}', '\u{a8ff}'), ('\u{a954}', '\u{a95e}'), ('\u{a97d}', '\u{a97f}'), ('\u{a9ce}', - '\u{a9ce}'), ('\u{a9da}', '\u{a9dd}'), ('\u{a9ff}', '\u{a9ff}'), ('\u{aa37}', '\u{aa3f}'), - ('\u{aa4e}', '\u{aa4f}'), ('\u{aa5a}', '\u{aa5b}'), ('\u{aac3}', '\u{aada}'), ('\u{aaf7}', - '\u{ab00}'), ('\u{ab07}', '\u{ab08}'), ('\u{ab0f}', '\u{ab10}'), ('\u{ab17}', '\u{ab1f}'), - ('\u{ab27}', '\u{ab27}'), ('\u{ab2f}', '\u{ab2f}'), ('\u{ab60}', '\u{ab63}'), ('\u{ab66}', - '\u{abbf}'), ('\u{abee}', '\u{abef}'), ('\u{abfa}', '\u{abff}'), ('\u{d7a4}', '\u{d7af}'), - ('\u{d7c7}', '\u{d7ca}'), ('\u{d7fc}', '\u{d7ff}'), ('\u{fa6e}', '\u{fa6f}'), ('\u{fada}', - '\u{faff}'), ('\u{fb07}', '\u{fb12}'), ('\u{fb18}', '\u{fb1c}'), ('\u{fb37}', '\u{fb37}'), - ('\u{fb3d}', '\u{fb3d}'), ('\u{fb3f}', '\u{fb3f}'), ('\u{fb42}', '\u{fb42}'), ('\u{fb45}', - '\u{fb45}'), ('\u{fbc2}', '\u{fbd2}'), ('\u{fd40}', '\u{fd4f}'), ('\u{fd90}', '\u{fd91}'), - ('\u{fdc8}', '\u{fdef}'), ('\u{fdfe}', '\u{fdff}'), ('\u{fe1a}', '\u{fe1f}'), ('\u{fe2e}', - '\u{fe2f}'), ('\u{fe53}', '\u{fe53}'), ('\u{fe67}', '\u{fe67}'), ('\u{fe6c}', '\u{fe6f}'), - ('\u{fe75}', '\u{fe75}'), ('\u{fefd}', '\u{fefe}'), ('\u{ff00}', '\u{ff00}'), ('\u{ffbf}', - '\u{ffc1}'), ('\u{ffc8}', '\u{ffc9}'), ('\u{ffd0}', '\u{ffd1}'), ('\u{ffd8}', '\u{ffd9}'), - ('\u{ffdd}', '\u{ffdf}'), ('\u{ffe7}', '\u{ffe7}'), ('\u{ffef}', '\u{fff8}'), ('\u{fffe}', - '\u{ffff}'), ('\u{1000c}', '\u{1000c}'), ('\u{10027}', '\u{10027}'), ('\u{1003b}', - '\u{1003b}'), ('\u{1003e}', '\u{1003e}'), ('\u{1004e}', '\u{1004f}'), ('\u{1005e}', - '\u{1007f}'), ('\u{100fb}', '\u{100ff}'), ('\u{10103}', '\u{10106}'), ('\u{10134}', - '\u{10136}'), ('\u{1018d}', '\u{1018f}'), ('\u{1019c}', '\u{1019f}'), ('\u{101a1}', - '\u{101cf}'), ('\u{101fe}', '\u{1027f}'), ('\u{1029d}', '\u{1029f}'), ('\u{102d1}', - '\u{102df}'), ('\u{102fc}', '\u{102ff}'), ('\u{10324}', '\u{1032f}'), ('\u{1034b}', - '\u{1034f}'), ('\u{1037b}', '\u{1037f}'), ('\u{1039e}', '\u{1039e}'), ('\u{103c4}', - '\u{103c7}'), ('\u{103d6}', '\u{103ff}'), ('\u{1049e}', '\u{1049f}'), ('\u{104aa}', - '\u{104ff}'), ('\u{10528}', '\u{1052f}'), ('\u{10564}', '\u{1056e}'), ('\u{10570}', - '\u{105ff}'), ('\u{10737}', '\u{1073f}'), ('\u{10756}', '\u{1075f}'), ('\u{10768}', - '\u{107ff}'), ('\u{10806}', '\u{10807}'), ('\u{10809}', '\u{10809}'), ('\u{10836}', - '\u{10836}'), ('\u{10839}', '\u{1083b}'), ('\u{1083d}', '\u{1083e}'), ('\u{10856}', - '\u{10856}'), ('\u{1089f}', '\u{108a6}'), ('\u{108b0}', '\u{108ff}'), ('\u{1091c}', - '\u{1091e}'), ('\u{1093a}', '\u{1093e}'), ('\u{10940}', '\u{1097f}'), ('\u{109b8}', - '\u{109bd}'), ('\u{109c0}', '\u{109ff}'), ('\u{10a04}', '\u{10a04}'), ('\u{10a07}', - '\u{10a0b}'), ('\u{10a14}', '\u{10a14}'), ('\u{10a18}', '\u{10a18}'), ('\u{10a34}', - '\u{10a37}'), ('\u{10a3b}', '\u{10a3e}'), ('\u{10a48}', '\u{10a4f}'), ('\u{10a59}', - '\u{10a5f}'), ('\u{10aa0}', '\u{10abf}'), ('\u{10ae7}', '\u{10aea}'), ('\u{10af7}', - '\u{10aff}'), ('\u{10b36}', '\u{10b38}'), ('\u{10b56}', '\u{10b57}'), ('\u{10b73}', - '\u{10b77}'), ('\u{10b92}', '\u{10b98}'), ('\u{10b9d}', '\u{10ba8}'), ('\u{10bb0}', - '\u{10bff}'), ('\u{10c49}', '\u{10e5f}'), ('\u{10e7f}', '\u{10fff}'), ('\u{1104e}', - '\u{11051}'), ('\u{11070}', '\u{1107e}'), ('\u{110c2}', '\u{110cf}'), ('\u{110e9}', - '\u{110ef}'), ('\u{110fa}', '\u{110ff}'), ('\u{11135}', '\u{11135}'), ('\u{11144}', - '\u{1114f}'), ('\u{11177}', '\u{1117f}'), ('\u{111c9}', '\u{111cc}'), ('\u{111ce}', - '\u{111cf}'), ('\u{111db}', '\u{111e0}'), ('\u{111f5}', '\u{111ff}'), ('\u{11212}', - '\u{11212}'), ('\u{1123e}', '\u{112af}'), ('\u{112eb}', '\u{112ef}'), ('\u{112fa}', - '\u{11300}'), ('\u{11304}', '\u{11304}'), ('\u{1130d}', '\u{1130e}'), ('\u{11311}', - '\u{11312}'), ('\u{11329}', '\u{11329}'), ('\u{11331}', '\u{11331}'), ('\u{11334}', - '\u{11334}'), ('\u{1133a}', '\u{1133b}'), ('\u{11345}', '\u{11346}'), ('\u{11349}', - '\u{1134a}'), ('\u{1134e}', '\u{11356}'), ('\u{11358}', '\u{1135c}'), ('\u{11364}', - '\u{11365}'), ('\u{1136d}', '\u{1136f}'), ('\u{11375}', '\u{1147f}'), ('\u{114c8}', - '\u{114cf}'), ('\u{114da}', '\u{1157f}'), ('\u{115b6}', '\u{115b7}'), ('\u{115ca}', - '\u{115ff}'), ('\u{11645}', '\u{1164f}'), ('\u{1165a}', '\u{1167f}'), ('\u{116b8}', - '\u{116bf}'), ('\u{116ca}', '\u{1189f}'), ('\u{118f3}', '\u{118fe}'), ('\u{11900}', - '\u{11abf}'), ('\u{11af9}', '\u{11fff}'), ('\u{12399}', '\u{123ff}'), ('\u{1246f}', - '\u{1246f}'), ('\u{12475}', '\u{12fff}'), ('\u{1342f}', '\u{167ff}'), ('\u{16a39}', - '\u{16a3f}'), ('\u{16a5f}', '\u{16a5f}'), ('\u{16a6a}', '\u{16a6d}'), ('\u{16a70}', - '\u{16acf}'), ('\u{16aee}', '\u{16aef}'), ('\u{16af6}', '\u{16aff}'), ('\u{16b46}', - '\u{16b4f}'), ('\u{16b5a}', '\u{16b5a}'), ('\u{16b62}', '\u{16b62}'), ('\u{16b78}', - '\u{16b7c}'), ('\u{16b90}', '\u{16eff}'), ('\u{16f45}', '\u{16f4f}'), ('\u{16f7f}', - '\u{16f8e}'), ('\u{16fa0}', '\u{1afff}'), ('\u{1b002}', '\u{1bbff}'), ('\u{1bc6b}', - '\u{1bc6f}'), ('\u{1bc7d}', '\u{1bc7f}'), ('\u{1bc89}', '\u{1bc8f}'), ('\u{1bc9a}', - '\u{1bc9b}'), ('\u{1bca4}', '\u{1cfff}'), ('\u{1d0f6}', '\u{1d0ff}'), ('\u{1d127}', - '\u{1d128}'), ('\u{1d1de}', '\u{1d1ff}'), ('\u{1d246}', '\u{1d2ff}'), ('\u{1d357}', - '\u{1d35f}'), ('\u{1d372}', '\u{1d3ff}'), ('\u{1d455}', '\u{1d455}'), ('\u{1d49d}', - '\u{1d49d}'), ('\u{1d4a0}', '\u{1d4a1}'), ('\u{1d4a3}', '\u{1d4a4}'), ('\u{1d4a7}', - '\u{1d4a8}'), ('\u{1d4ad}', '\u{1d4ad}'), ('\u{1d4ba}', '\u{1d4ba}'), ('\u{1d4bc}', - '\u{1d4bc}'), ('\u{1d4c4}', '\u{1d4c4}'), ('\u{1d506}', '\u{1d506}'), ('\u{1d50b}', - '\u{1d50c}'), ('\u{1d515}', '\u{1d515}'), ('\u{1d51d}', '\u{1d51d}'), ('\u{1d53a}', - '\u{1d53a}'), ('\u{1d53f}', '\u{1d53f}'), ('\u{1d545}', '\u{1d545}'), ('\u{1d547}', - '\u{1d549}'), ('\u{1d551}', '\u{1d551}'), ('\u{1d6a6}', '\u{1d6a7}'), ('\u{1d7cc}', - '\u{1d7cd}'), ('\u{1d800}', '\u{1e7ff}'), ('\u{1e8c5}', '\u{1e8c6}'), ('\u{1e8d7}', - '\u{1edff}'), ('\u{1ee04}', '\u{1ee04}'), ('\u{1ee20}', '\u{1ee20}'), ('\u{1ee23}', - '\u{1ee23}'), ('\u{1ee25}', '\u{1ee26}'), ('\u{1ee28}', '\u{1ee28}'), ('\u{1ee33}', - '\u{1ee33}'), ('\u{1ee38}', '\u{1ee38}'), ('\u{1ee3a}', '\u{1ee3a}'), ('\u{1ee3c}', - '\u{1ee41}'), ('\u{1ee43}', '\u{1ee46}'), ('\u{1ee48}', '\u{1ee48}'), ('\u{1ee4a}', - '\u{1ee4a}'), ('\u{1ee4c}', '\u{1ee4c}'), ('\u{1ee50}', '\u{1ee50}'), ('\u{1ee53}', - '\u{1ee53}'), ('\u{1ee55}', '\u{1ee56}'), ('\u{1ee58}', '\u{1ee58}'), ('\u{1ee5a}', - '\u{1ee5a}'), ('\u{1ee5c}', '\u{1ee5c}'), ('\u{1ee5e}', '\u{1ee5e}'), ('\u{1ee60}', - '\u{1ee60}'), ('\u{1ee63}', '\u{1ee63}'), ('\u{1ee65}', '\u{1ee66}'), ('\u{1ee6b}', - '\u{1ee6b}'), ('\u{1ee73}', '\u{1ee73}'), ('\u{1ee78}', '\u{1ee78}'), ('\u{1ee7d}', - '\u{1ee7d}'), ('\u{1ee7f}', '\u{1ee7f}'), ('\u{1ee8a}', '\u{1ee8a}'), ('\u{1ee9c}', - '\u{1eea0}'), ('\u{1eea4}', '\u{1eea4}'), ('\u{1eeaa}', '\u{1eeaa}'), ('\u{1eebc}', - '\u{1eeef}'), ('\u{1eef2}', '\u{1efff}'), ('\u{1f02c}', '\u{1f02f}'), ('\u{1f094}', - '\u{1f09f}'), ('\u{1f0af}', '\u{1f0b0}'), ('\u{1f0c0}', '\u{1f0c0}'), ('\u{1f0d0}', - '\u{1f0d0}'), ('\u{1f0f6}', '\u{1f0ff}'), ('\u{1f10d}', '\u{1f10f}'), ('\u{1f12f}', - '\u{1f12f}'), ('\u{1f16c}', '\u{1f16f}'), ('\u{1f19b}', '\u{1f1e5}'), ('\u{1f203}', - '\u{1f20f}'), ('\u{1f23b}', '\u{1f23f}'), ('\u{1f249}', '\u{1f24f}'), ('\u{1f252}', - '\u{1f2ff}'), ('\u{1f32d}', '\u{1f32f}'), ('\u{1f37e}', '\u{1f37f}'), ('\u{1f3cf}', - '\u{1f3d3}'), ('\u{1f3f8}', '\u{1f3ff}'), ('\u{1f4ff}', '\u{1f4ff}'), ('\u{1f54b}', - '\u{1f54f}'), ('\u{1f57a}', '\u{1f57a}'), ('\u{1f5a4}', '\u{1f5a4}'), ('\u{1f643}', - '\u{1f644}'), ('\u{1f6d0}', '\u{1f6df}'), ('\u{1f6ed}', '\u{1f6ef}'), ('\u{1f6f4}', - '\u{1f6ff}'), ('\u{1f774}', '\u{1f77f}'), ('\u{1f7d5}', '\u{1f7ff}'), ('\u{1f80c}', - '\u{1f80f}'), ('\u{1f848}', '\u{1f84f}'), ('\u{1f85a}', '\u{1f85f}'), ('\u{1f888}', - '\u{1f88f}'), ('\u{1f8ae}', '\u{1ffff}'), ('\u{2a6d7}', '\u{2a6ff}'), ('\u{2b735}', - '\u{2b73f}'), ('\u{2b81e}', '\u{2f7ff}'), ('\u{2fa1e}', '\u{e0000}'), ('\u{e0002}', - '\u{e001f}'), ('\u{e0080}', '\u{e00ff}'), ('\u{e01f0}', '\u{effff}'), ('\u{ffffe}', - '\u{fffff}'), ('\u{10fffe}', '\u{10ffff}') - ]; - - pub const Co_table: &'static [(char, char)] = &[ - ('\u{e000}', '\u{f8ff}'), ('\u{f0000}', '\u{ffffd}'), ('\u{100000}', '\u{10fffd}') - ]; - - pub const L_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), - ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), - ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', - '\u{2ee}'), ('\u{370}', '\u{374}'), ('\u{376}', '\u{377}'), ('\u{37a}', '\u{37d}'), - ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', - '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'), - ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{561}', - '\u{587}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{620}', '\u{64a}'), - ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}', - '\u{6e6}'), ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), - ('\u{710}', '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}', - '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), - ('\u{800}', '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}', - '\u{828}'), ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b2}'), ('\u{904}', '\u{939}'), - ('\u{93d}', '\u{93d}'), ('\u{950}', '\u{950}'), ('\u{958}', '\u{961}'), ('\u{971}', - '\u{980}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), - ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bd}', - '\u{9bd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e1}'), - ('\u{9f0}', '\u{9f1}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), ('\u{a13}', - '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', '\u{a36}'), - ('\u{a38}', '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a72}', - '\u{a74}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), - ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', - '\u{abd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{b05}', '\u{b0c}'), - ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', - '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b3d}'), ('\u{b5c}', '\u{b5d}'), - ('\u{b5f}', '\u{b61}'), ('\u{b71}', '\u{b71}'), ('\u{b83}', '\u{b83}'), ('\u{b85}', - '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), - ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', - '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), ('\u{c05}', '\u{c0c}'), - ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', - '\u{c3d}'), ('\u{c58}', '\u{c59}'), ('\u{c60}', '\u{c61}'), ('\u{c85}', '\u{c8c}'), - ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), ('\u{cb5}', - '\u{cb9}'), ('\u{cbd}', '\u{cbd}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', '\u{ce1}'), - ('\u{cf1}', '\u{cf2}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', - '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d60}', '\u{d61}'), - ('\u{d7a}', '\u{d7f}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', - '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', '\u{e30}'), - ('\u{e32}', '\u{e33}'), ('\u{e40}', '\u{e46}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', - '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), - ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', - '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', '\u{eb0}'), - ('\u{eb2}', '\u{eb3}'), ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', - '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f40}', '\u{f47}'), - ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), ('\u{1000}', '\u{102a}'), ('\u{103f}', - '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', '\u{105d}'), ('\u{1061}', '\u{1061}'), - ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), ('\u{1075}', '\u{1081}'), ('\u{108e}', - '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), - ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', - '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), - ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', - '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), - ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}', - '\u{138f}'), ('\u{13a0}', '\u{13f4}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), - ('\u{1681}', '\u{169a}'), ('\u{16a0}', '\u{16ea}'), ('\u{16f1}', '\u{16f8}'), ('\u{1700}', - '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1720}', '\u{1731}'), ('\u{1740}', '\u{1751}'), - ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1780}', '\u{17b3}'), ('\u{17d7}', - '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1877}'), ('\u{1880}', '\u{18a8}'), - ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1950}', - '\u{196d}'), ('\u{1970}', '\u{1974}'), ('\u{1980}', '\u{19ab}'), ('\u{19c1}', '\u{19c7}'), - ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', '\u{1a54}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b05}', - '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b83}', '\u{1ba0}'), ('\u{1bae}', '\u{1baf}'), - ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', '\u{1c23}'), ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', - '\u{1c7d}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), ('\u{1cf5}', '\u{1cf6}'), - ('\u{1d00}', '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', - '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), - ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', - '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), - ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', - '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{2071}', '\u{2071}'), - ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', - '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'), - ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', - '\u{212d}'), ('\u{212f}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'), - ('\u{214e}', '\u{214e}'), ('\u{2183}', '\u{2184}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', - '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), - ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', - '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d80}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), - ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', - '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), - ('\u{2e2f}', '\u{2e2f}'), ('\u{3005}', '\u{3006}'), ('\u{3031}', '\u{3035}'), ('\u{303b}', - '\u{303c}'), ('\u{3041}', '\u{3096}'), ('\u{309d}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), - ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', '\u{318e}'), ('\u{31a0}', - '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fcc}'), - ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}', '\u{a60c}'), ('\u{a610}', - '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', '\u{a66e}'), ('\u{a67f}', '\u{a69d}'), - ('\u{a6a0}', '\u{a6e5}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'), ('\u{a78b}', - '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b1}'), ('\u{a7f7}', '\u{a801}'), - ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a822}'), ('\u{a840}', - '\u{a873}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), - ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), ('\u{a960}', '\u{a97c}'), ('\u{a984}', - '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), ('\u{a9e6}', '\u{a9ef}'), - ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', '\u{aa28}'), ('\u{aa40}', '\u{aa42}'), ('\u{aa44}', - '\u{aa4b}'), ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), ('\u{aa7e}', '\u{aaaf}'), - ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', '\u{aabd}'), ('\u{aac0}', - '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), ('\u{aae0}', '\u{aaea}'), - ('\u{aaf2}', '\u{aaf4}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', - '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), - ('\u{ab5c}', '\u{ab5f}'), ('\u{ab64}', '\u{ab65}'), ('\u{abc0}', '\u{abe2}'), ('\u{ac00}', - '\u{d7a3}'), ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), - ('\u{fa70}', '\u{fad9}'), ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', - '\u{fb1d}'), ('\u{fb1f}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), - ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', - '\u{fbb1}'), ('\u{fbd3}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), - ('\u{fdf0}', '\u{fdfb}'), ('\u{fe70}', '\u{fe74}'), ('\u{fe76}', '\u{fefc}'), ('\u{ff21}', - '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', '\u{ffc7}'), - ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), ('\u{10000}', - '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), ('\u{1003c}', - '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), ('\u{10080}', - '\u{100fa}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{10300}', - '\u{1031f}'), ('\u{10330}', '\u{10340}'), ('\u{10342}', '\u{10349}'), ('\u{10350}', - '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', - '\u{103cf}'), ('\u{10400}', '\u{1049d}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', - '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', - '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', - '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', - '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{10900}', - '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', - '\u{109bf}'), ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', - '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', - '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', - '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', - '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{11003}', '\u{11037}'), ('\u{11083}', - '\u{110af}'), ('\u{110d0}', '\u{110e8}'), ('\u{11103}', '\u{11126}'), ('\u{11150}', - '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11183}', '\u{111b2}'), ('\u{111c1}', - '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', - '\u{1122b}'), ('\u{112b0}', '\u{112de}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', - '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', - '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}', '\u{1133d}'), ('\u{1135d}', - '\u{11361}'), ('\u{11480}', '\u{114af}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', - '\u{114c7}'), ('\u{11580}', '\u{115ae}'), ('\u{11600}', '\u{1162f}'), ('\u{11644}', - '\u{11644}'), ('\u{11680}', '\u{116aa}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', - '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{12000}', '\u{12398}'), ('\u{13000}', - '\u{1342e}'), ('\u{16800}', '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', - '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b63}', - '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', - '\u{16f50}'), ('\u{16f93}', '\u{16f9f}'), ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', - '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', - '\u{1bc99}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', - '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', - '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', - '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', - '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', - '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', - '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', - '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', - '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', - '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', - '\u{1d7cb}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', - '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', - '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', - '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', - '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', - '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', - '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', - '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', - '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', - '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', - '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', - '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', - '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', '\u{2fa1d}') - ]; - - pub const LC_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{b5}', '\u{b5}'), ('\u{c0}', '\u{d6}'), - ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'), ('\u{1bc}', '\u{1bf}'), ('\u{1c4}', '\u{293}'), - ('\u{295}', '\u{2af}'), ('\u{370}', '\u{373}'), ('\u{376}', '\u{377}'), ('\u{37b}', - '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), - ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', - '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{561}', '\u{587}'), - ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{1d00}', - '\u{1d2b}'), ('\u{1d6b}', '\u{1d77}'), ('\u{1d79}', '\u{1d9a}'), ('\u{1e00}', '\u{1f15}'), - ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', - '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), - ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', - '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), - ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', - '\u{1ffc}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), - ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', - '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), ('\u{212f}', '\u{2134}'), - ('\u{2139}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', - '\u{214e}'), ('\u{2183}', '\u{2184}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), - ('\u{2c60}', '\u{2c7b}'), ('\u{2c7e}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', - '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), - ('\u{a640}', '\u{a66d}'), ('\u{a680}', '\u{a69b}'), ('\u{a722}', '\u{a76f}'), ('\u{a771}', - '\u{a787}'), ('\u{a78b}', '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b1}'), - ('\u{a7fa}', '\u{a7fa}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab64}', '\u{ab65}'), ('\u{fb00}', - '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), - ('\u{10400}', '\u{1044f}'), ('\u{118a0}', '\u{118df}'), ('\u{1d400}', '\u{1d454}'), - ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), - ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), - ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), - ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), - ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), - ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), - ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), - ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), - ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), - ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}') - ]; - - pub const Ll_table: &'static [(char, char)] = &[ - ('\u{61}', '\u{7a}'), ('\u{b5}', '\u{b5}'), ('\u{df}', '\u{f6}'), ('\u{f8}', '\u{ff}'), - ('\u{101}', '\u{101}'), ('\u{103}', '\u{103}'), ('\u{105}', '\u{105}'), ('\u{107}', - '\u{107}'), ('\u{109}', '\u{109}'), ('\u{10b}', '\u{10b}'), ('\u{10d}', '\u{10d}'), - ('\u{10f}', '\u{10f}'), ('\u{111}', '\u{111}'), ('\u{113}', '\u{113}'), ('\u{115}', - '\u{115}'), ('\u{117}', '\u{117}'), ('\u{119}', '\u{119}'), ('\u{11b}', '\u{11b}'), - ('\u{11d}', '\u{11d}'), ('\u{11f}', '\u{11f}'), ('\u{121}', '\u{121}'), ('\u{123}', - '\u{123}'), ('\u{125}', '\u{125}'), ('\u{127}', '\u{127}'), ('\u{129}', '\u{129}'), - ('\u{12b}', '\u{12b}'), ('\u{12d}', '\u{12d}'), ('\u{12f}', '\u{12f}'), ('\u{131}', - '\u{131}'), ('\u{133}', '\u{133}'), ('\u{135}', '\u{135}'), ('\u{137}', '\u{138}'), - ('\u{13a}', '\u{13a}'), ('\u{13c}', '\u{13c}'), ('\u{13e}', '\u{13e}'), ('\u{140}', - '\u{140}'), ('\u{142}', '\u{142}'), ('\u{144}', '\u{144}'), ('\u{146}', '\u{146}'), - ('\u{148}', '\u{149}'), ('\u{14b}', '\u{14b}'), ('\u{14d}', '\u{14d}'), ('\u{14f}', - '\u{14f}'), ('\u{151}', '\u{151}'), ('\u{153}', '\u{153}'), ('\u{155}', '\u{155}'), - ('\u{157}', '\u{157}'), ('\u{159}', '\u{159}'), ('\u{15b}', '\u{15b}'), ('\u{15d}', - '\u{15d}'), ('\u{15f}', '\u{15f}'), ('\u{161}', '\u{161}'), ('\u{163}', '\u{163}'), - ('\u{165}', '\u{165}'), ('\u{167}', '\u{167}'), ('\u{169}', '\u{169}'), ('\u{16b}', - '\u{16b}'), ('\u{16d}', '\u{16d}'), ('\u{16f}', '\u{16f}'), ('\u{171}', '\u{171}'), - ('\u{173}', '\u{173}'), ('\u{175}', '\u{175}'), ('\u{177}', '\u{177}'), ('\u{17a}', - '\u{17a}'), ('\u{17c}', '\u{17c}'), ('\u{17e}', '\u{180}'), ('\u{183}', '\u{183}'), - ('\u{185}', '\u{185}'), ('\u{188}', '\u{188}'), ('\u{18c}', '\u{18d}'), ('\u{192}', - '\u{192}'), ('\u{195}', '\u{195}'), ('\u{199}', '\u{19b}'), ('\u{19e}', '\u{19e}'), - ('\u{1a1}', '\u{1a1}'), ('\u{1a3}', '\u{1a3}'), ('\u{1a5}', '\u{1a5}'), ('\u{1a8}', - '\u{1a8}'), ('\u{1aa}', '\u{1ab}'), ('\u{1ad}', '\u{1ad}'), ('\u{1b0}', '\u{1b0}'), - ('\u{1b4}', '\u{1b4}'), ('\u{1b6}', '\u{1b6}'), ('\u{1b9}', '\u{1ba}'), ('\u{1bd}', - '\u{1bf}'), ('\u{1c6}', '\u{1c6}'), ('\u{1c9}', '\u{1c9}'), ('\u{1cc}', '\u{1cc}'), - ('\u{1ce}', '\u{1ce}'), ('\u{1d0}', '\u{1d0}'), ('\u{1d2}', '\u{1d2}'), ('\u{1d4}', - '\u{1d4}'), ('\u{1d6}', '\u{1d6}'), ('\u{1d8}', '\u{1d8}'), ('\u{1da}', '\u{1da}'), - ('\u{1dc}', '\u{1dd}'), ('\u{1df}', '\u{1df}'), ('\u{1e1}', '\u{1e1}'), ('\u{1e3}', - '\u{1e3}'), ('\u{1e5}', '\u{1e5}'), ('\u{1e7}', '\u{1e7}'), ('\u{1e9}', '\u{1e9}'), - ('\u{1eb}', '\u{1eb}'), ('\u{1ed}', '\u{1ed}'), ('\u{1ef}', '\u{1f0}'), ('\u{1f3}', - '\u{1f3}'), ('\u{1f5}', '\u{1f5}'), ('\u{1f9}', '\u{1f9}'), ('\u{1fb}', '\u{1fb}'), - ('\u{1fd}', '\u{1fd}'), ('\u{1ff}', '\u{1ff}'), ('\u{201}', '\u{201}'), ('\u{203}', - '\u{203}'), ('\u{205}', '\u{205}'), ('\u{207}', '\u{207}'), ('\u{209}', '\u{209}'), - ('\u{20b}', '\u{20b}'), ('\u{20d}', '\u{20d}'), ('\u{20f}', '\u{20f}'), ('\u{211}', - '\u{211}'), ('\u{213}', '\u{213}'), ('\u{215}', '\u{215}'), ('\u{217}', '\u{217}'), - ('\u{219}', '\u{219}'), ('\u{21b}', '\u{21b}'), ('\u{21d}', '\u{21d}'), ('\u{21f}', - '\u{21f}'), ('\u{221}', '\u{221}'), ('\u{223}', '\u{223}'), ('\u{225}', '\u{225}'), - ('\u{227}', '\u{227}'), ('\u{229}', '\u{229}'), ('\u{22b}', '\u{22b}'), ('\u{22d}', - '\u{22d}'), ('\u{22f}', '\u{22f}'), ('\u{231}', '\u{231}'), ('\u{233}', '\u{239}'), - ('\u{23c}', '\u{23c}'), ('\u{23f}', '\u{240}'), ('\u{242}', '\u{242}'), ('\u{247}', - '\u{247}'), ('\u{249}', '\u{249}'), ('\u{24b}', '\u{24b}'), ('\u{24d}', '\u{24d}'), - ('\u{24f}', '\u{293}'), ('\u{295}', '\u{2af}'), ('\u{371}', '\u{371}'), ('\u{373}', - '\u{373}'), ('\u{377}', '\u{377}'), ('\u{37b}', '\u{37d}'), ('\u{390}', '\u{390}'), - ('\u{3ac}', '\u{3ce}'), ('\u{3d0}', '\u{3d1}'), ('\u{3d5}', '\u{3d7}'), ('\u{3d9}', - '\u{3d9}'), ('\u{3db}', '\u{3db}'), ('\u{3dd}', '\u{3dd}'), ('\u{3df}', '\u{3df}'), - ('\u{3e1}', '\u{3e1}'), ('\u{3e3}', '\u{3e3}'), ('\u{3e5}', '\u{3e5}'), ('\u{3e7}', - '\u{3e7}'), ('\u{3e9}', '\u{3e9}'), ('\u{3eb}', '\u{3eb}'), ('\u{3ed}', '\u{3ed}'), - ('\u{3ef}', '\u{3f3}'), ('\u{3f5}', '\u{3f5}'), ('\u{3f8}', '\u{3f8}'), ('\u{3fb}', - '\u{3fc}'), ('\u{430}', '\u{45f}'), ('\u{461}', '\u{461}'), ('\u{463}', '\u{463}'), - ('\u{465}', '\u{465}'), ('\u{467}', '\u{467}'), ('\u{469}', '\u{469}'), ('\u{46b}', - '\u{46b}'), ('\u{46d}', '\u{46d}'), ('\u{46f}', '\u{46f}'), ('\u{471}', '\u{471}'), - ('\u{473}', '\u{473}'), ('\u{475}', '\u{475}'), ('\u{477}', '\u{477}'), ('\u{479}', - '\u{479}'), ('\u{47b}', '\u{47b}'), ('\u{47d}', '\u{47d}'), ('\u{47f}', '\u{47f}'), - ('\u{481}', '\u{481}'), ('\u{48b}', '\u{48b}'), ('\u{48d}', '\u{48d}'), ('\u{48f}', - '\u{48f}'), ('\u{491}', '\u{491}'), ('\u{493}', '\u{493}'), ('\u{495}', '\u{495}'), - ('\u{497}', '\u{497}'), ('\u{499}', '\u{499}'), ('\u{49b}', '\u{49b}'), ('\u{49d}', - '\u{49d}'), ('\u{49f}', '\u{49f}'), ('\u{4a1}', '\u{4a1}'), ('\u{4a3}', '\u{4a3}'), - ('\u{4a5}', '\u{4a5}'), ('\u{4a7}', '\u{4a7}'), ('\u{4a9}', '\u{4a9}'), ('\u{4ab}', - '\u{4ab}'), ('\u{4ad}', '\u{4ad}'), ('\u{4af}', '\u{4af}'), ('\u{4b1}', '\u{4b1}'), - ('\u{4b3}', '\u{4b3}'), ('\u{4b5}', '\u{4b5}'), ('\u{4b7}', '\u{4b7}'), ('\u{4b9}', - '\u{4b9}'), ('\u{4bb}', '\u{4bb}'), ('\u{4bd}', '\u{4bd}'), ('\u{4bf}', '\u{4bf}'), - ('\u{4c2}', '\u{4c2}'), ('\u{4c4}', '\u{4c4}'), ('\u{4c6}', '\u{4c6}'), ('\u{4c8}', - '\u{4c8}'), ('\u{4ca}', '\u{4ca}'), ('\u{4cc}', '\u{4cc}'), ('\u{4ce}', '\u{4cf}'), - ('\u{4d1}', '\u{4d1}'), ('\u{4d3}', '\u{4d3}'), ('\u{4d5}', '\u{4d5}'), ('\u{4d7}', - '\u{4d7}'), ('\u{4d9}', '\u{4d9}'), ('\u{4db}', '\u{4db}'), ('\u{4dd}', '\u{4dd}'), - ('\u{4df}', '\u{4df}'), ('\u{4e1}', '\u{4e1}'), ('\u{4e3}', '\u{4e3}'), ('\u{4e5}', - '\u{4e5}'), ('\u{4e7}', '\u{4e7}'), ('\u{4e9}', '\u{4e9}'), ('\u{4eb}', '\u{4eb}'), - ('\u{4ed}', '\u{4ed}'), ('\u{4ef}', '\u{4ef}'), ('\u{4f1}', '\u{4f1}'), ('\u{4f3}', - '\u{4f3}'), ('\u{4f5}', '\u{4f5}'), ('\u{4f7}', '\u{4f7}'), ('\u{4f9}', '\u{4f9}'), - ('\u{4fb}', '\u{4fb}'), ('\u{4fd}', '\u{4fd}'), ('\u{4ff}', '\u{4ff}'), ('\u{501}', - '\u{501}'), ('\u{503}', '\u{503}'), ('\u{505}', '\u{505}'), ('\u{507}', '\u{507}'), - ('\u{509}', '\u{509}'), ('\u{50b}', '\u{50b}'), ('\u{50d}', '\u{50d}'), ('\u{50f}', - '\u{50f}'), ('\u{511}', '\u{511}'), ('\u{513}', '\u{513}'), ('\u{515}', '\u{515}'), - ('\u{517}', '\u{517}'), ('\u{519}', '\u{519}'), ('\u{51b}', '\u{51b}'), ('\u{51d}', - '\u{51d}'), ('\u{51f}', '\u{51f}'), ('\u{521}', '\u{521}'), ('\u{523}', '\u{523}'), - ('\u{525}', '\u{525}'), ('\u{527}', '\u{527}'), ('\u{529}', '\u{529}'), ('\u{52b}', - '\u{52b}'), ('\u{52d}', '\u{52d}'), ('\u{52f}', '\u{52f}'), ('\u{561}', '\u{587}'), - ('\u{1d00}', '\u{1d2b}'), ('\u{1d6b}', '\u{1d77}'), ('\u{1d79}', '\u{1d9a}'), ('\u{1e01}', - '\u{1e01}'), ('\u{1e03}', '\u{1e03}'), ('\u{1e05}', '\u{1e05}'), ('\u{1e07}', '\u{1e07}'), - ('\u{1e09}', '\u{1e09}'), ('\u{1e0b}', '\u{1e0b}'), ('\u{1e0d}', '\u{1e0d}'), ('\u{1e0f}', - '\u{1e0f}'), ('\u{1e11}', '\u{1e11}'), ('\u{1e13}', '\u{1e13}'), ('\u{1e15}', '\u{1e15}'), - ('\u{1e17}', '\u{1e17}'), ('\u{1e19}', '\u{1e19}'), ('\u{1e1b}', '\u{1e1b}'), ('\u{1e1d}', - '\u{1e1d}'), ('\u{1e1f}', '\u{1e1f}'), ('\u{1e21}', '\u{1e21}'), ('\u{1e23}', '\u{1e23}'), - ('\u{1e25}', '\u{1e25}'), ('\u{1e27}', '\u{1e27}'), ('\u{1e29}', '\u{1e29}'), ('\u{1e2b}', - '\u{1e2b}'), ('\u{1e2d}', '\u{1e2d}'), ('\u{1e2f}', '\u{1e2f}'), ('\u{1e31}', '\u{1e31}'), - ('\u{1e33}', '\u{1e33}'), ('\u{1e35}', '\u{1e35}'), ('\u{1e37}', '\u{1e37}'), ('\u{1e39}', - '\u{1e39}'), ('\u{1e3b}', '\u{1e3b}'), ('\u{1e3d}', '\u{1e3d}'), ('\u{1e3f}', '\u{1e3f}'), - ('\u{1e41}', '\u{1e41}'), ('\u{1e43}', '\u{1e43}'), ('\u{1e45}', '\u{1e45}'), ('\u{1e47}', - '\u{1e47}'), ('\u{1e49}', '\u{1e49}'), ('\u{1e4b}', '\u{1e4b}'), ('\u{1e4d}', '\u{1e4d}'), - ('\u{1e4f}', '\u{1e4f}'), ('\u{1e51}', '\u{1e51}'), ('\u{1e53}', '\u{1e53}'), ('\u{1e55}', - '\u{1e55}'), ('\u{1e57}', '\u{1e57}'), ('\u{1e59}', '\u{1e59}'), ('\u{1e5b}', '\u{1e5b}'), - ('\u{1e5d}', '\u{1e5d}'), ('\u{1e5f}', '\u{1e5f}'), ('\u{1e61}', '\u{1e61}'), ('\u{1e63}', - '\u{1e63}'), ('\u{1e65}', '\u{1e65}'), ('\u{1e67}', '\u{1e67}'), ('\u{1e69}', '\u{1e69}'), - ('\u{1e6b}', '\u{1e6b}'), ('\u{1e6d}', '\u{1e6d}'), ('\u{1e6f}', '\u{1e6f}'), ('\u{1e71}', - '\u{1e71}'), ('\u{1e73}', '\u{1e73}'), ('\u{1e75}', '\u{1e75}'), ('\u{1e77}', '\u{1e77}'), - ('\u{1e79}', '\u{1e79}'), ('\u{1e7b}', '\u{1e7b}'), ('\u{1e7d}', '\u{1e7d}'), ('\u{1e7f}', - '\u{1e7f}'), ('\u{1e81}', '\u{1e81}'), ('\u{1e83}', '\u{1e83}'), ('\u{1e85}', '\u{1e85}'), - ('\u{1e87}', '\u{1e87}'), ('\u{1e89}', '\u{1e89}'), ('\u{1e8b}', '\u{1e8b}'), ('\u{1e8d}', - '\u{1e8d}'), ('\u{1e8f}', '\u{1e8f}'), ('\u{1e91}', '\u{1e91}'), ('\u{1e93}', '\u{1e93}'), - ('\u{1e95}', '\u{1e9d}'), ('\u{1e9f}', '\u{1e9f}'), ('\u{1ea1}', '\u{1ea1}'), ('\u{1ea3}', - '\u{1ea3}'), ('\u{1ea5}', '\u{1ea5}'), ('\u{1ea7}', '\u{1ea7}'), ('\u{1ea9}', '\u{1ea9}'), - ('\u{1eab}', '\u{1eab}'), ('\u{1ead}', '\u{1ead}'), ('\u{1eaf}', '\u{1eaf}'), ('\u{1eb1}', - '\u{1eb1}'), ('\u{1eb3}', '\u{1eb3}'), ('\u{1eb5}', '\u{1eb5}'), ('\u{1eb7}', '\u{1eb7}'), - ('\u{1eb9}', '\u{1eb9}'), ('\u{1ebb}', '\u{1ebb}'), ('\u{1ebd}', '\u{1ebd}'), ('\u{1ebf}', - '\u{1ebf}'), ('\u{1ec1}', '\u{1ec1}'), ('\u{1ec3}', '\u{1ec3}'), ('\u{1ec5}', '\u{1ec5}'), - ('\u{1ec7}', '\u{1ec7}'), ('\u{1ec9}', '\u{1ec9}'), ('\u{1ecb}', '\u{1ecb}'), ('\u{1ecd}', - '\u{1ecd}'), ('\u{1ecf}', '\u{1ecf}'), ('\u{1ed1}', '\u{1ed1}'), ('\u{1ed3}', '\u{1ed3}'), - ('\u{1ed5}', '\u{1ed5}'), ('\u{1ed7}', '\u{1ed7}'), ('\u{1ed9}', '\u{1ed9}'), ('\u{1edb}', - '\u{1edb}'), ('\u{1edd}', '\u{1edd}'), ('\u{1edf}', '\u{1edf}'), ('\u{1ee1}', '\u{1ee1}'), - ('\u{1ee3}', '\u{1ee3}'), ('\u{1ee5}', '\u{1ee5}'), ('\u{1ee7}', '\u{1ee7}'), ('\u{1ee9}', - '\u{1ee9}'), ('\u{1eeb}', '\u{1eeb}'), ('\u{1eed}', '\u{1eed}'), ('\u{1eef}', '\u{1eef}'), - ('\u{1ef1}', '\u{1ef1}'), ('\u{1ef3}', '\u{1ef3}'), ('\u{1ef5}', '\u{1ef5}'), ('\u{1ef7}', - '\u{1ef7}'), ('\u{1ef9}', '\u{1ef9}'), ('\u{1efb}', '\u{1efb}'), ('\u{1efd}', '\u{1efd}'), - ('\u{1eff}', '\u{1f07}'), ('\u{1f10}', '\u{1f15}'), ('\u{1f20}', '\u{1f27}'), ('\u{1f30}', - '\u{1f37}'), ('\u{1f40}', '\u{1f45}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f60}', '\u{1f67}'), - ('\u{1f70}', '\u{1f7d}'), ('\u{1f80}', '\u{1f87}'), ('\u{1f90}', '\u{1f97}'), ('\u{1fa0}', - '\u{1fa7}'), ('\u{1fb0}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fb7}'), ('\u{1fbe}', '\u{1fbe}'), - ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fc7}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', - '\u{1fd7}'), ('\u{1fe0}', '\u{1fe7}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ff7}'), - ('\u{210a}', '\u{210a}'), ('\u{210e}', '\u{210f}'), ('\u{2113}', '\u{2113}'), ('\u{212f}', - '\u{212f}'), ('\u{2134}', '\u{2134}'), ('\u{2139}', '\u{2139}'), ('\u{213c}', '\u{213d}'), - ('\u{2146}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2184}', '\u{2184}'), ('\u{2c30}', - '\u{2c5e}'), ('\u{2c61}', '\u{2c61}'), ('\u{2c65}', '\u{2c66}'), ('\u{2c68}', '\u{2c68}'), - ('\u{2c6a}', '\u{2c6a}'), ('\u{2c6c}', '\u{2c6c}'), ('\u{2c71}', '\u{2c71}'), ('\u{2c73}', - '\u{2c74}'), ('\u{2c76}', '\u{2c7b}'), ('\u{2c81}', '\u{2c81}'), ('\u{2c83}', '\u{2c83}'), - ('\u{2c85}', '\u{2c85}'), ('\u{2c87}', '\u{2c87}'), ('\u{2c89}', '\u{2c89}'), ('\u{2c8b}', - '\u{2c8b}'), ('\u{2c8d}', '\u{2c8d}'), ('\u{2c8f}', '\u{2c8f}'), ('\u{2c91}', '\u{2c91}'), - ('\u{2c93}', '\u{2c93}'), ('\u{2c95}', '\u{2c95}'), ('\u{2c97}', '\u{2c97}'), ('\u{2c99}', - '\u{2c99}'), ('\u{2c9b}', '\u{2c9b}'), ('\u{2c9d}', '\u{2c9d}'), ('\u{2c9f}', '\u{2c9f}'), - ('\u{2ca1}', '\u{2ca1}'), ('\u{2ca3}', '\u{2ca3}'), ('\u{2ca5}', '\u{2ca5}'), ('\u{2ca7}', - '\u{2ca7}'), ('\u{2ca9}', '\u{2ca9}'), ('\u{2cab}', '\u{2cab}'), ('\u{2cad}', '\u{2cad}'), - ('\u{2caf}', '\u{2caf}'), ('\u{2cb1}', '\u{2cb1}'), ('\u{2cb3}', '\u{2cb3}'), ('\u{2cb5}', - '\u{2cb5}'), ('\u{2cb7}', '\u{2cb7}'), ('\u{2cb9}', '\u{2cb9}'), ('\u{2cbb}', '\u{2cbb}'), - ('\u{2cbd}', '\u{2cbd}'), ('\u{2cbf}', '\u{2cbf}'), ('\u{2cc1}', '\u{2cc1}'), ('\u{2cc3}', - '\u{2cc3}'), ('\u{2cc5}', '\u{2cc5}'), ('\u{2cc7}', '\u{2cc7}'), ('\u{2cc9}', '\u{2cc9}'), - ('\u{2ccb}', '\u{2ccb}'), ('\u{2ccd}', '\u{2ccd}'), ('\u{2ccf}', '\u{2ccf}'), ('\u{2cd1}', - '\u{2cd1}'), ('\u{2cd3}', '\u{2cd3}'), ('\u{2cd5}', '\u{2cd5}'), ('\u{2cd7}', '\u{2cd7}'), - ('\u{2cd9}', '\u{2cd9}'), ('\u{2cdb}', '\u{2cdb}'), ('\u{2cdd}', '\u{2cdd}'), ('\u{2cdf}', - '\u{2cdf}'), ('\u{2ce1}', '\u{2ce1}'), ('\u{2ce3}', '\u{2ce4}'), ('\u{2cec}', '\u{2cec}'), - ('\u{2cee}', '\u{2cee}'), ('\u{2cf3}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', - '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{a641}', '\u{a641}'), ('\u{a643}', '\u{a643}'), - ('\u{a645}', '\u{a645}'), ('\u{a647}', '\u{a647}'), ('\u{a649}', '\u{a649}'), ('\u{a64b}', - '\u{a64b}'), ('\u{a64d}', '\u{a64d}'), ('\u{a64f}', '\u{a64f}'), ('\u{a651}', '\u{a651}'), - ('\u{a653}', '\u{a653}'), ('\u{a655}', '\u{a655}'), ('\u{a657}', '\u{a657}'), ('\u{a659}', - '\u{a659}'), ('\u{a65b}', '\u{a65b}'), ('\u{a65d}', '\u{a65d}'), ('\u{a65f}', '\u{a65f}'), - ('\u{a661}', '\u{a661}'), ('\u{a663}', '\u{a663}'), ('\u{a665}', '\u{a665}'), ('\u{a667}', - '\u{a667}'), ('\u{a669}', '\u{a669}'), ('\u{a66b}', '\u{a66b}'), ('\u{a66d}', '\u{a66d}'), - ('\u{a681}', '\u{a681}'), ('\u{a683}', '\u{a683}'), ('\u{a685}', '\u{a685}'), ('\u{a687}', - '\u{a687}'), ('\u{a689}', '\u{a689}'), ('\u{a68b}', '\u{a68b}'), ('\u{a68d}', '\u{a68d}'), - ('\u{a68f}', '\u{a68f}'), ('\u{a691}', '\u{a691}'), ('\u{a693}', '\u{a693}'), ('\u{a695}', - '\u{a695}'), ('\u{a697}', '\u{a697}'), ('\u{a699}', '\u{a699}'), ('\u{a69b}', '\u{a69b}'), - ('\u{a723}', '\u{a723}'), ('\u{a725}', '\u{a725}'), ('\u{a727}', '\u{a727}'), ('\u{a729}', - '\u{a729}'), ('\u{a72b}', '\u{a72b}'), ('\u{a72d}', '\u{a72d}'), ('\u{a72f}', '\u{a731}'), - ('\u{a733}', '\u{a733}'), ('\u{a735}', '\u{a735}'), ('\u{a737}', '\u{a737}'), ('\u{a739}', - '\u{a739}'), ('\u{a73b}', '\u{a73b}'), ('\u{a73d}', '\u{a73d}'), ('\u{a73f}', '\u{a73f}'), - ('\u{a741}', '\u{a741}'), ('\u{a743}', '\u{a743}'), ('\u{a745}', '\u{a745}'), ('\u{a747}', - '\u{a747}'), ('\u{a749}', '\u{a749}'), ('\u{a74b}', '\u{a74b}'), ('\u{a74d}', '\u{a74d}'), - ('\u{a74f}', '\u{a74f}'), ('\u{a751}', '\u{a751}'), ('\u{a753}', '\u{a753}'), ('\u{a755}', - '\u{a755}'), ('\u{a757}', '\u{a757}'), ('\u{a759}', '\u{a759}'), ('\u{a75b}', '\u{a75b}'), - ('\u{a75d}', '\u{a75d}'), ('\u{a75f}', '\u{a75f}'), ('\u{a761}', '\u{a761}'), ('\u{a763}', - '\u{a763}'), ('\u{a765}', '\u{a765}'), ('\u{a767}', '\u{a767}'), ('\u{a769}', '\u{a769}'), - ('\u{a76b}', '\u{a76b}'), ('\u{a76d}', '\u{a76d}'), ('\u{a76f}', '\u{a76f}'), ('\u{a771}', - '\u{a778}'), ('\u{a77a}', '\u{a77a}'), ('\u{a77c}', '\u{a77c}'), ('\u{a77f}', '\u{a77f}'), - ('\u{a781}', '\u{a781}'), ('\u{a783}', '\u{a783}'), ('\u{a785}', '\u{a785}'), ('\u{a787}', - '\u{a787}'), ('\u{a78c}', '\u{a78c}'), ('\u{a78e}', '\u{a78e}'), ('\u{a791}', '\u{a791}'), - ('\u{a793}', '\u{a795}'), ('\u{a797}', '\u{a797}'), ('\u{a799}', '\u{a799}'), ('\u{a79b}', - '\u{a79b}'), ('\u{a79d}', '\u{a79d}'), ('\u{a79f}', '\u{a79f}'), ('\u{a7a1}', '\u{a7a1}'), - ('\u{a7a3}', '\u{a7a3}'), ('\u{a7a5}', '\u{a7a5}'), ('\u{a7a7}', '\u{a7a7}'), ('\u{a7a9}', - '\u{a7a9}'), ('\u{a7fa}', '\u{a7fa}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab64}', '\u{ab65}'), - ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{ff41}', '\u{ff5a}'), ('\u{10428}', - '\u{1044f}'), ('\u{118c0}', '\u{118df}'), ('\u{1d41a}', '\u{1d433}'), ('\u{1d44e}', - '\u{1d454}'), ('\u{1d456}', '\u{1d467}'), ('\u{1d482}', '\u{1d49b}'), ('\u{1d4b6}', - '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', - '\u{1d4cf}'), ('\u{1d4ea}', '\u{1d503}'), ('\u{1d51e}', '\u{1d537}'), ('\u{1d552}', - '\u{1d56b}'), ('\u{1d586}', '\u{1d59f}'), ('\u{1d5ba}', '\u{1d5d3}'), ('\u{1d5ee}', - '\u{1d607}'), ('\u{1d622}', '\u{1d63b}'), ('\u{1d656}', '\u{1d66f}'), ('\u{1d68a}', - '\u{1d6a5}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6e1}'), ('\u{1d6fc}', - '\u{1d714}'), ('\u{1d716}', '\u{1d71b}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', - '\u{1d755}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d78f}'), ('\u{1d7aa}', - '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7c9}'), ('\u{1d7cb}', '\u{1d7cb}') - ]; - - pub const Lm_table: &'static [(char, char)] = &[ - ('\u{2b0}', '\u{2c1}'), ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', - '\u{2ec}'), ('\u{2ee}', '\u{2ee}'), ('\u{374}', '\u{374}'), ('\u{37a}', '\u{37a}'), - ('\u{559}', '\u{559}'), ('\u{640}', '\u{640}'), ('\u{6e5}', '\u{6e6}'), ('\u{7f4}', - '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), - ('\u{828}', '\u{828}'), ('\u{971}', '\u{971}'), ('\u{e46}', '\u{e46}'), ('\u{ec6}', - '\u{ec6}'), ('\u{10fc}', '\u{10fc}'), ('\u{17d7}', '\u{17d7}'), ('\u{1843}', '\u{1843}'), - ('\u{1aa7}', '\u{1aa7}'), ('\u{1c78}', '\u{1c7d}'), ('\u{1d2c}', '\u{1d6a}'), ('\u{1d78}', - '\u{1d78}'), ('\u{1d9b}', '\u{1dbf}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), - ('\u{2090}', '\u{209c}'), ('\u{2c7c}', '\u{2c7d}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2e2f}', - '\u{2e2f}'), ('\u{3005}', '\u{3005}'), ('\u{3031}', '\u{3035}'), ('\u{303b}', '\u{303b}'), - ('\u{309d}', '\u{309e}'), ('\u{30fc}', '\u{30fe}'), ('\u{a015}', '\u{a015}'), ('\u{a4f8}', - '\u{a4fd}'), ('\u{a60c}', '\u{a60c}'), ('\u{a67f}', '\u{a67f}'), ('\u{a69c}', '\u{a69d}'), - ('\u{a717}', '\u{a71f}'), ('\u{a770}', '\u{a770}'), ('\u{a788}', '\u{a788}'), ('\u{a7f8}', - '\u{a7f9}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e6}', '\u{a9e6}'), ('\u{aa70}', '\u{aa70}'), - ('\u{aadd}', '\u{aadd}'), ('\u{aaf3}', '\u{aaf4}'), ('\u{ab5c}', '\u{ab5f}'), ('\u{ff70}', - '\u{ff70}'), ('\u{ff9e}', '\u{ff9f}'), ('\u{16b40}', '\u{16b43}'), ('\u{16f93}', - '\u{16f9f}') - ]; - - pub const Lo_table: &'static [(char, char)] = &[ - ('\u{aa}', '\u{aa}'), ('\u{ba}', '\u{ba}'), ('\u{1bb}', '\u{1bb}'), ('\u{1c0}', '\u{1c3}'), - ('\u{294}', '\u{294}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{620}', - '\u{63f}'), ('\u{641}', '\u{64a}'), ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), - ('\u{6d5}', '\u{6d5}'), ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', - '\u{6ff}'), ('\u{710}', '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), - ('\u{7b1}', '\u{7b1}'), ('\u{7ca}', '\u{7ea}'), ('\u{800}', '\u{815}'), ('\u{840}', - '\u{858}'), ('\u{8a0}', '\u{8b2}'), ('\u{904}', '\u{939}'), ('\u{93d}', '\u{93d}'), - ('\u{950}', '\u{950}'), ('\u{958}', '\u{961}'), ('\u{972}', '\u{980}'), ('\u{985}', - '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), - ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bd}', '\u{9bd}'), ('\u{9ce}', - '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e1}'), ('\u{9f0}', '\u{9f1}'), - ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', - '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), - ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a72}', '\u{a74}'), ('\u{a85}', - '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), - ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abd}', '\u{abd}'), ('\u{ad0}', - '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{b05}', '\u{b0c}'), ('\u{b0f}', '\u{b10}'), - ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', '\u{b33}'), ('\u{b35}', - '\u{b39}'), ('\u{b3d}', '\u{b3d}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b61}'), - ('\u{b71}', '\u{b71}'), ('\u{b83}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', - '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), - ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', - '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), ('\u{c05}', '\u{c0c}'), ('\u{c0e}', '\u{c10}'), - ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c3d}'), ('\u{c58}', - '\u{c59}'), ('\u{c60}', '\u{c61}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), - ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', - '\u{cbd}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', '\u{ce1}'), ('\u{cf1}', '\u{cf2}'), - ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', - '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d60}', '\u{d61}'), ('\u{d7a}', '\u{d7f}'), - ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), ('\u{dbd}', - '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', '\u{e30}'), ('\u{e32}', '\u{e33}'), - ('\u{e40}', '\u{e45}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', - '\u{e88}'), ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), - ('\u{e99}', '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', - '\u{ea7}'), ('\u{eaa}', '\u{eab}'), ('\u{ead}', '\u{eb0}'), ('\u{eb2}', '\u{eb3}'), - ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', '\u{ec4}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', - '\u{f00}'), ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), - ('\u{1000}', '\u{102a}'), ('\u{103f}', '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', - '\u{105d}'), ('\u{1061}', '\u{1061}'), ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), - ('\u{1075}', '\u{1081}'), ('\u{108e}', '\u{108e}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fd}', - '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'), - ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}', - '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'), - ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}', - '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f4}'), - ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', - '\u{16ea}'), ('\u{16f1}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1711}'), - ('\u{1720}', '\u{1731}'), ('\u{1740}', '\u{1751}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', - '\u{1770}'), ('\u{1780}', '\u{17b3}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1842}'), - ('\u{1844}', '\u{1877}'), ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', - '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), - ('\u{1980}', '\u{19ab}'), ('\u{19c1}', '\u{19c7}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', - '\u{1a54}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b83}', '\u{1ba0}'), - ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', '\u{1c23}'), ('\u{1c4d}', - '\u{1c4f}'), ('\u{1c5a}', '\u{1c77}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), - ('\u{1cf5}', '\u{1cf6}'), ('\u{2135}', '\u{2138}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d80}', - '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), - ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', - '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{3006}', '\u{3006}'), ('\u{303c}', '\u{303c}'), - ('\u{3041}', '\u{3096}'), ('\u{309f}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), ('\u{30ff}', - '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', '\u{318e}'), ('\u{31a0}', '\u{31ba}'), - ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fcc}'), ('\u{a000}', - '\u{a014}'), ('\u{a016}', '\u{a48c}'), ('\u{a4d0}', '\u{a4f7}'), ('\u{a500}', '\u{a60b}'), - ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a66e}', '\u{a66e}'), ('\u{a6a0}', - '\u{a6e5}'), ('\u{a7f7}', '\u{a7f7}'), ('\u{a7fb}', '\u{a801}'), ('\u{a803}', '\u{a805}'), - ('\u{a807}', '\u{a80a}'), ('\u{a80c}', '\u{a822}'), ('\u{a840}', '\u{a873}'), ('\u{a882}', - '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), ('\u{a90a}', '\u{a925}'), - ('\u{a930}', '\u{a946}'), ('\u{a960}', '\u{a97c}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9e0}', - '\u{a9e4}'), ('\u{a9e7}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', '\u{aa28}'), - ('\u{aa40}', '\u{aa42}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa6f}'), ('\u{aa71}', - '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), ('\u{aa7e}', '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), - ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', '\u{aabd}'), ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', - '\u{aac2}'), ('\u{aadb}', '\u{aadc}'), ('\u{aae0}', '\u{aaea}'), ('\u{aaf2}', '\u{aaf2}'), - ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', - '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{abc0}', '\u{abe2}'), ('\u{ac00}', '\u{d7a3}'), - ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', - '\u{fad9}'), ('\u{fb1d}', '\u{fb1d}'), ('\u{fb1f}', '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), - ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', - '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), - ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdfb}'), ('\u{fe70}', '\u{fe74}'), ('\u{fe76}', - '\u{fefc}'), ('\u{ff66}', '\u{ff6f}'), ('\u{ff71}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), - ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', - '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', - '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', - '\u{1005d}'), ('\u{10080}', '\u{100fa}'), ('\u{10280}', '\u{1029c}'), ('\u{102a0}', - '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', '\u{10340}'), ('\u{10342}', - '\u{10349}'), ('\u{10350}', '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', - '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{10450}', '\u{1049d}'), ('\u{10500}', - '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', - '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', - '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', - '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', - '\u{1089e}'), ('\u{10900}', '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', - '\u{109b7}'), ('\u{109be}', '\u{109bf}'), ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', - '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', - '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', - '\u{10ae4}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', - '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{11003}', - '\u{11037}'), ('\u{11083}', '\u{110af}'), ('\u{110d0}', '\u{110e8}'), ('\u{11103}', - '\u{11126}'), ('\u{11150}', '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11183}', - '\u{111b2}'), ('\u{111c1}', '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{11200}', - '\u{11211}'), ('\u{11213}', '\u{1122b}'), ('\u{112b0}', '\u{112de}'), ('\u{11305}', - '\u{1130c}'), ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', - '\u{11330}'), ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}', - '\u{1133d}'), ('\u{1135d}', '\u{11361}'), ('\u{11480}', '\u{114af}'), ('\u{114c4}', - '\u{114c5}'), ('\u{114c7}', '\u{114c7}'), ('\u{11580}', '\u{115ae}'), ('\u{11600}', - '\u{1162f}'), ('\u{11644}', '\u{11644}'), ('\u{11680}', '\u{116aa}'), ('\u{118ff}', - '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{12000}', '\u{12398}'), ('\u{13000}', - '\u{1342e}'), ('\u{16800}', '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16ad0}', - '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', - '\u{16b8f}'), ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{1b000}', - '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', - '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1ee00}', - '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', - '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', - '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', - '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', - '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', - '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', - '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', - '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', - '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', - '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', - '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', - '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', - '\u{2fa1d}') - ]; - - pub const Lt_table: &'static [(char, char)] = &[ - ('\u{1c5}', '\u{1c5}'), ('\u{1c8}', '\u{1c8}'), ('\u{1cb}', '\u{1cb}'), ('\u{1f2}', - '\u{1f2}'), ('\u{1f88}', '\u{1f8f}'), ('\u{1f98}', '\u{1f9f}'), ('\u{1fa8}', '\u{1faf}'), - ('\u{1fbc}', '\u{1fbc}'), ('\u{1fcc}', '\u{1fcc}'), ('\u{1ffc}', '\u{1ffc}') - ]; - - pub const Lu_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{de}'), ('\u{100}', '\u{100}'), - ('\u{102}', '\u{102}'), ('\u{104}', '\u{104}'), ('\u{106}', '\u{106}'), ('\u{108}', - '\u{108}'), ('\u{10a}', '\u{10a}'), ('\u{10c}', '\u{10c}'), ('\u{10e}', '\u{10e}'), - ('\u{110}', '\u{110}'), ('\u{112}', '\u{112}'), ('\u{114}', '\u{114}'), ('\u{116}', - '\u{116}'), ('\u{118}', '\u{118}'), ('\u{11a}', '\u{11a}'), ('\u{11c}', '\u{11c}'), - ('\u{11e}', '\u{11e}'), ('\u{120}', '\u{120}'), ('\u{122}', '\u{122}'), ('\u{124}', - '\u{124}'), ('\u{126}', '\u{126}'), ('\u{128}', '\u{128}'), ('\u{12a}', '\u{12a}'), - ('\u{12c}', '\u{12c}'), ('\u{12e}', '\u{12e}'), ('\u{130}', '\u{130}'), ('\u{132}', - '\u{132}'), ('\u{134}', '\u{134}'), ('\u{136}', '\u{136}'), ('\u{139}', '\u{139}'), - ('\u{13b}', '\u{13b}'), ('\u{13d}', '\u{13d}'), ('\u{13f}', '\u{13f}'), ('\u{141}', - '\u{141}'), ('\u{143}', '\u{143}'), ('\u{145}', '\u{145}'), ('\u{147}', '\u{147}'), - ('\u{14a}', '\u{14a}'), ('\u{14c}', '\u{14c}'), ('\u{14e}', '\u{14e}'), ('\u{150}', - '\u{150}'), ('\u{152}', '\u{152}'), ('\u{154}', '\u{154}'), ('\u{156}', '\u{156}'), - ('\u{158}', '\u{158}'), ('\u{15a}', '\u{15a}'), ('\u{15c}', '\u{15c}'), ('\u{15e}', - '\u{15e}'), ('\u{160}', '\u{160}'), ('\u{162}', '\u{162}'), ('\u{164}', '\u{164}'), - ('\u{166}', '\u{166}'), ('\u{168}', '\u{168}'), ('\u{16a}', '\u{16a}'), ('\u{16c}', - '\u{16c}'), ('\u{16e}', '\u{16e}'), ('\u{170}', '\u{170}'), ('\u{172}', '\u{172}'), - ('\u{174}', '\u{174}'), ('\u{176}', '\u{176}'), ('\u{178}', '\u{179}'), ('\u{17b}', - '\u{17b}'), ('\u{17d}', '\u{17d}'), ('\u{181}', '\u{182}'), ('\u{184}', '\u{184}'), - ('\u{186}', '\u{187}'), ('\u{189}', '\u{18b}'), ('\u{18e}', '\u{191}'), ('\u{193}', - '\u{194}'), ('\u{196}', '\u{198}'), ('\u{19c}', '\u{19d}'), ('\u{19f}', '\u{1a0}'), - ('\u{1a2}', '\u{1a2}'), ('\u{1a4}', '\u{1a4}'), ('\u{1a6}', '\u{1a7}'), ('\u{1a9}', - '\u{1a9}'), ('\u{1ac}', '\u{1ac}'), ('\u{1ae}', '\u{1af}'), ('\u{1b1}', '\u{1b3}'), - ('\u{1b5}', '\u{1b5}'), ('\u{1b7}', '\u{1b8}'), ('\u{1bc}', '\u{1bc}'), ('\u{1c4}', - '\u{1c4}'), ('\u{1c7}', '\u{1c7}'), ('\u{1ca}', '\u{1ca}'), ('\u{1cd}', '\u{1cd}'), - ('\u{1cf}', '\u{1cf}'), ('\u{1d1}', '\u{1d1}'), ('\u{1d3}', '\u{1d3}'), ('\u{1d5}', - '\u{1d5}'), ('\u{1d7}', '\u{1d7}'), ('\u{1d9}', '\u{1d9}'), ('\u{1db}', '\u{1db}'), - ('\u{1de}', '\u{1de}'), ('\u{1e0}', '\u{1e0}'), ('\u{1e2}', '\u{1e2}'), ('\u{1e4}', - '\u{1e4}'), ('\u{1e6}', '\u{1e6}'), ('\u{1e8}', '\u{1e8}'), ('\u{1ea}', '\u{1ea}'), - ('\u{1ec}', '\u{1ec}'), ('\u{1ee}', '\u{1ee}'), ('\u{1f1}', '\u{1f1}'), ('\u{1f4}', - '\u{1f4}'), ('\u{1f6}', '\u{1f8}'), ('\u{1fa}', '\u{1fa}'), ('\u{1fc}', '\u{1fc}'), - ('\u{1fe}', '\u{1fe}'), ('\u{200}', '\u{200}'), ('\u{202}', '\u{202}'), ('\u{204}', - '\u{204}'), ('\u{206}', '\u{206}'), ('\u{208}', '\u{208}'), ('\u{20a}', '\u{20a}'), - ('\u{20c}', '\u{20c}'), ('\u{20e}', '\u{20e}'), ('\u{210}', '\u{210}'), ('\u{212}', - '\u{212}'), ('\u{214}', '\u{214}'), ('\u{216}', '\u{216}'), ('\u{218}', '\u{218}'), - ('\u{21a}', '\u{21a}'), ('\u{21c}', '\u{21c}'), ('\u{21e}', '\u{21e}'), ('\u{220}', - '\u{220}'), ('\u{222}', '\u{222}'), ('\u{224}', '\u{224}'), ('\u{226}', '\u{226}'), - ('\u{228}', '\u{228}'), ('\u{22a}', '\u{22a}'), ('\u{22c}', '\u{22c}'), ('\u{22e}', - '\u{22e}'), ('\u{230}', '\u{230}'), ('\u{232}', '\u{232}'), ('\u{23a}', '\u{23b}'), - ('\u{23d}', '\u{23e}'), ('\u{241}', '\u{241}'), ('\u{243}', '\u{246}'), ('\u{248}', - '\u{248}'), ('\u{24a}', '\u{24a}'), ('\u{24c}', '\u{24c}'), ('\u{24e}', '\u{24e}'), - ('\u{370}', '\u{370}'), ('\u{372}', '\u{372}'), ('\u{376}', '\u{376}'), ('\u{37f}', - '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), - ('\u{38e}', '\u{38f}'), ('\u{391}', '\u{3a1}'), ('\u{3a3}', '\u{3ab}'), ('\u{3cf}', - '\u{3cf}'), ('\u{3d2}', '\u{3d4}'), ('\u{3d8}', '\u{3d8}'), ('\u{3da}', '\u{3da}'), - ('\u{3dc}', '\u{3dc}'), ('\u{3de}', '\u{3de}'), ('\u{3e0}', '\u{3e0}'), ('\u{3e2}', - '\u{3e2}'), ('\u{3e4}', '\u{3e4}'), ('\u{3e6}', '\u{3e6}'), ('\u{3e8}', '\u{3e8}'), - ('\u{3ea}', '\u{3ea}'), ('\u{3ec}', '\u{3ec}'), ('\u{3ee}', '\u{3ee}'), ('\u{3f4}', - '\u{3f4}'), ('\u{3f7}', '\u{3f7}'), ('\u{3f9}', '\u{3fa}'), ('\u{3fd}', '\u{42f}'), - ('\u{460}', '\u{460}'), ('\u{462}', '\u{462}'), ('\u{464}', '\u{464}'), ('\u{466}', - '\u{466}'), ('\u{468}', '\u{468}'), ('\u{46a}', '\u{46a}'), ('\u{46c}', '\u{46c}'), - ('\u{46e}', '\u{46e}'), ('\u{470}', '\u{470}'), ('\u{472}', '\u{472}'), ('\u{474}', - '\u{474}'), ('\u{476}', '\u{476}'), ('\u{478}', '\u{478}'), ('\u{47a}', '\u{47a}'), - ('\u{47c}', '\u{47c}'), ('\u{47e}', '\u{47e}'), ('\u{480}', '\u{480}'), ('\u{48a}', - '\u{48a}'), ('\u{48c}', '\u{48c}'), ('\u{48e}', '\u{48e}'), ('\u{490}', '\u{490}'), - ('\u{492}', '\u{492}'), ('\u{494}', '\u{494}'), ('\u{496}', '\u{496}'), ('\u{498}', - '\u{498}'), ('\u{49a}', '\u{49a}'), ('\u{49c}', '\u{49c}'), ('\u{49e}', '\u{49e}'), - ('\u{4a0}', '\u{4a0}'), ('\u{4a2}', '\u{4a2}'), ('\u{4a4}', '\u{4a4}'), ('\u{4a6}', - '\u{4a6}'), ('\u{4a8}', '\u{4a8}'), ('\u{4aa}', '\u{4aa}'), ('\u{4ac}', '\u{4ac}'), - ('\u{4ae}', '\u{4ae}'), ('\u{4b0}', '\u{4b0}'), ('\u{4b2}', '\u{4b2}'), ('\u{4b4}', - '\u{4b4}'), ('\u{4b6}', '\u{4b6}'), ('\u{4b8}', '\u{4b8}'), ('\u{4ba}', '\u{4ba}'), - ('\u{4bc}', '\u{4bc}'), ('\u{4be}', '\u{4be}'), ('\u{4c0}', '\u{4c1}'), ('\u{4c3}', - '\u{4c3}'), ('\u{4c5}', '\u{4c5}'), ('\u{4c7}', '\u{4c7}'), ('\u{4c9}', '\u{4c9}'), - ('\u{4cb}', '\u{4cb}'), ('\u{4cd}', '\u{4cd}'), ('\u{4d0}', '\u{4d0}'), ('\u{4d2}', - '\u{4d2}'), ('\u{4d4}', '\u{4d4}'), ('\u{4d6}', '\u{4d6}'), ('\u{4d8}', '\u{4d8}'), - ('\u{4da}', '\u{4da}'), ('\u{4dc}', '\u{4dc}'), ('\u{4de}', '\u{4de}'), ('\u{4e0}', - '\u{4e0}'), ('\u{4e2}', '\u{4e2}'), ('\u{4e4}', '\u{4e4}'), ('\u{4e6}', '\u{4e6}'), - ('\u{4e8}', '\u{4e8}'), ('\u{4ea}', '\u{4ea}'), ('\u{4ec}', '\u{4ec}'), ('\u{4ee}', - '\u{4ee}'), ('\u{4f0}', '\u{4f0}'), ('\u{4f2}', '\u{4f2}'), ('\u{4f4}', '\u{4f4}'), - ('\u{4f6}', '\u{4f6}'), ('\u{4f8}', '\u{4f8}'), ('\u{4fa}', '\u{4fa}'), ('\u{4fc}', - '\u{4fc}'), ('\u{4fe}', '\u{4fe}'), ('\u{500}', '\u{500}'), ('\u{502}', '\u{502}'), - ('\u{504}', '\u{504}'), ('\u{506}', '\u{506}'), ('\u{508}', '\u{508}'), ('\u{50a}', - '\u{50a}'), ('\u{50c}', '\u{50c}'), ('\u{50e}', '\u{50e}'), ('\u{510}', '\u{510}'), - ('\u{512}', '\u{512}'), ('\u{514}', '\u{514}'), ('\u{516}', '\u{516}'), ('\u{518}', - '\u{518}'), ('\u{51a}', '\u{51a}'), ('\u{51c}', '\u{51c}'), ('\u{51e}', '\u{51e}'), - ('\u{520}', '\u{520}'), ('\u{522}', '\u{522}'), ('\u{524}', '\u{524}'), ('\u{526}', - '\u{526}'), ('\u{528}', '\u{528}'), ('\u{52a}', '\u{52a}'), ('\u{52c}', '\u{52c}'), - ('\u{52e}', '\u{52e}'), ('\u{531}', '\u{556}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', - '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{1e00}', '\u{1e00}'), ('\u{1e02}', '\u{1e02}'), - ('\u{1e04}', '\u{1e04}'), ('\u{1e06}', '\u{1e06}'), ('\u{1e08}', '\u{1e08}'), ('\u{1e0a}', - '\u{1e0a}'), ('\u{1e0c}', '\u{1e0c}'), ('\u{1e0e}', '\u{1e0e}'), ('\u{1e10}', '\u{1e10}'), - ('\u{1e12}', '\u{1e12}'), ('\u{1e14}', '\u{1e14}'), ('\u{1e16}', '\u{1e16}'), ('\u{1e18}', - '\u{1e18}'), ('\u{1e1a}', '\u{1e1a}'), ('\u{1e1c}', '\u{1e1c}'), ('\u{1e1e}', '\u{1e1e}'), - ('\u{1e20}', '\u{1e20}'), ('\u{1e22}', '\u{1e22}'), ('\u{1e24}', '\u{1e24}'), ('\u{1e26}', - '\u{1e26}'), ('\u{1e28}', '\u{1e28}'), ('\u{1e2a}', '\u{1e2a}'), ('\u{1e2c}', '\u{1e2c}'), - ('\u{1e2e}', '\u{1e2e}'), ('\u{1e30}', '\u{1e30}'), ('\u{1e32}', '\u{1e32}'), ('\u{1e34}', - '\u{1e34}'), ('\u{1e36}', '\u{1e36}'), ('\u{1e38}', '\u{1e38}'), ('\u{1e3a}', '\u{1e3a}'), - ('\u{1e3c}', '\u{1e3c}'), ('\u{1e3e}', '\u{1e3e}'), ('\u{1e40}', '\u{1e40}'), ('\u{1e42}', - '\u{1e42}'), ('\u{1e44}', '\u{1e44}'), ('\u{1e46}', '\u{1e46}'), ('\u{1e48}', '\u{1e48}'), - ('\u{1e4a}', '\u{1e4a}'), ('\u{1e4c}', '\u{1e4c}'), ('\u{1e4e}', '\u{1e4e}'), ('\u{1e50}', - '\u{1e50}'), ('\u{1e52}', '\u{1e52}'), ('\u{1e54}', '\u{1e54}'), ('\u{1e56}', '\u{1e56}'), - ('\u{1e58}', '\u{1e58}'), ('\u{1e5a}', '\u{1e5a}'), ('\u{1e5c}', '\u{1e5c}'), ('\u{1e5e}', - '\u{1e5e}'), ('\u{1e60}', '\u{1e60}'), ('\u{1e62}', '\u{1e62}'), ('\u{1e64}', '\u{1e64}'), - ('\u{1e66}', '\u{1e66}'), ('\u{1e68}', '\u{1e68}'), ('\u{1e6a}', '\u{1e6a}'), ('\u{1e6c}', - '\u{1e6c}'), ('\u{1e6e}', '\u{1e6e}'), ('\u{1e70}', '\u{1e70}'), ('\u{1e72}', '\u{1e72}'), - ('\u{1e74}', '\u{1e74}'), ('\u{1e76}', '\u{1e76}'), ('\u{1e78}', '\u{1e78}'), ('\u{1e7a}', - '\u{1e7a}'), ('\u{1e7c}', '\u{1e7c}'), ('\u{1e7e}', '\u{1e7e}'), ('\u{1e80}', '\u{1e80}'), - ('\u{1e82}', '\u{1e82}'), ('\u{1e84}', '\u{1e84}'), ('\u{1e86}', '\u{1e86}'), ('\u{1e88}', - '\u{1e88}'), ('\u{1e8a}', '\u{1e8a}'), ('\u{1e8c}', '\u{1e8c}'), ('\u{1e8e}', '\u{1e8e}'), - ('\u{1e90}', '\u{1e90}'), ('\u{1e92}', '\u{1e92}'), ('\u{1e94}', '\u{1e94}'), ('\u{1e9e}', - '\u{1e9e}'), ('\u{1ea0}', '\u{1ea0}'), ('\u{1ea2}', '\u{1ea2}'), ('\u{1ea4}', '\u{1ea4}'), - ('\u{1ea6}', '\u{1ea6}'), ('\u{1ea8}', '\u{1ea8}'), ('\u{1eaa}', '\u{1eaa}'), ('\u{1eac}', - '\u{1eac}'), ('\u{1eae}', '\u{1eae}'), ('\u{1eb0}', '\u{1eb0}'), ('\u{1eb2}', '\u{1eb2}'), - ('\u{1eb4}', '\u{1eb4}'), ('\u{1eb6}', '\u{1eb6}'), ('\u{1eb8}', '\u{1eb8}'), ('\u{1eba}', - '\u{1eba}'), ('\u{1ebc}', '\u{1ebc}'), ('\u{1ebe}', '\u{1ebe}'), ('\u{1ec0}', '\u{1ec0}'), - ('\u{1ec2}', '\u{1ec2}'), ('\u{1ec4}', '\u{1ec4}'), ('\u{1ec6}', '\u{1ec6}'), ('\u{1ec8}', - '\u{1ec8}'), ('\u{1eca}', '\u{1eca}'), ('\u{1ecc}', '\u{1ecc}'), ('\u{1ece}', '\u{1ece}'), - ('\u{1ed0}', '\u{1ed0}'), ('\u{1ed2}', '\u{1ed2}'), ('\u{1ed4}', '\u{1ed4}'), ('\u{1ed6}', - '\u{1ed6}'), ('\u{1ed8}', '\u{1ed8}'), ('\u{1eda}', '\u{1eda}'), ('\u{1edc}', '\u{1edc}'), - ('\u{1ede}', '\u{1ede}'), ('\u{1ee0}', '\u{1ee0}'), ('\u{1ee2}', '\u{1ee2}'), ('\u{1ee4}', - '\u{1ee4}'), ('\u{1ee6}', '\u{1ee6}'), ('\u{1ee8}', '\u{1ee8}'), ('\u{1eea}', '\u{1eea}'), - ('\u{1eec}', '\u{1eec}'), ('\u{1eee}', '\u{1eee}'), ('\u{1ef0}', '\u{1ef0}'), ('\u{1ef2}', - '\u{1ef2}'), ('\u{1ef4}', '\u{1ef4}'), ('\u{1ef6}', '\u{1ef6}'), ('\u{1ef8}', '\u{1ef8}'), - ('\u{1efa}', '\u{1efa}'), ('\u{1efc}', '\u{1efc}'), ('\u{1efe}', '\u{1efe}'), ('\u{1f08}', - '\u{1f0f}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f28}', '\u{1f2f}'), ('\u{1f38}', '\u{1f3f}'), - ('\u{1f48}', '\u{1f4d}'), ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', - '\u{1f5d}'), ('\u{1f5f}', '\u{1f5f}'), ('\u{1f68}', '\u{1f6f}'), ('\u{1fb8}', '\u{1fbb}'), - ('\u{1fc8}', '\u{1fcb}'), ('\u{1fd8}', '\u{1fdb}'), ('\u{1fe8}', '\u{1fec}'), ('\u{1ff8}', - '\u{1ffb}'), ('\u{2102}', '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210b}', '\u{210d}'), - ('\u{2110}', '\u{2112}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', - '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), - ('\u{2130}', '\u{2133}'), ('\u{213e}', '\u{213f}'), ('\u{2145}', '\u{2145}'), ('\u{2183}', - '\u{2183}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c60}', '\u{2c60}'), ('\u{2c62}', '\u{2c64}'), - ('\u{2c67}', '\u{2c67}'), ('\u{2c69}', '\u{2c69}'), ('\u{2c6b}', '\u{2c6b}'), ('\u{2c6d}', - '\u{2c70}'), ('\u{2c72}', '\u{2c72}'), ('\u{2c75}', '\u{2c75}'), ('\u{2c7e}', '\u{2c80}'), - ('\u{2c82}', '\u{2c82}'), ('\u{2c84}', '\u{2c84}'), ('\u{2c86}', '\u{2c86}'), ('\u{2c88}', - '\u{2c88}'), ('\u{2c8a}', '\u{2c8a}'), ('\u{2c8c}', '\u{2c8c}'), ('\u{2c8e}', '\u{2c8e}'), - ('\u{2c90}', '\u{2c90}'), ('\u{2c92}', '\u{2c92}'), ('\u{2c94}', '\u{2c94}'), ('\u{2c96}', - '\u{2c96}'), ('\u{2c98}', '\u{2c98}'), ('\u{2c9a}', '\u{2c9a}'), ('\u{2c9c}', '\u{2c9c}'), - ('\u{2c9e}', '\u{2c9e}'), ('\u{2ca0}', '\u{2ca0}'), ('\u{2ca2}', '\u{2ca2}'), ('\u{2ca4}', - '\u{2ca4}'), ('\u{2ca6}', '\u{2ca6}'), ('\u{2ca8}', '\u{2ca8}'), ('\u{2caa}', '\u{2caa}'), - ('\u{2cac}', '\u{2cac}'), ('\u{2cae}', '\u{2cae}'), ('\u{2cb0}', '\u{2cb0}'), ('\u{2cb2}', - '\u{2cb2}'), ('\u{2cb4}', '\u{2cb4}'), ('\u{2cb6}', '\u{2cb6}'), ('\u{2cb8}', '\u{2cb8}'), - ('\u{2cba}', '\u{2cba}'), ('\u{2cbc}', '\u{2cbc}'), ('\u{2cbe}', '\u{2cbe}'), ('\u{2cc0}', - '\u{2cc0}'), ('\u{2cc2}', '\u{2cc2}'), ('\u{2cc4}', '\u{2cc4}'), ('\u{2cc6}', '\u{2cc6}'), - ('\u{2cc8}', '\u{2cc8}'), ('\u{2cca}', '\u{2cca}'), ('\u{2ccc}', '\u{2ccc}'), ('\u{2cce}', - '\u{2cce}'), ('\u{2cd0}', '\u{2cd0}'), ('\u{2cd2}', '\u{2cd2}'), ('\u{2cd4}', '\u{2cd4}'), - ('\u{2cd6}', '\u{2cd6}'), ('\u{2cd8}', '\u{2cd8}'), ('\u{2cda}', '\u{2cda}'), ('\u{2cdc}', - '\u{2cdc}'), ('\u{2cde}', '\u{2cde}'), ('\u{2ce0}', '\u{2ce0}'), ('\u{2ce2}', '\u{2ce2}'), - ('\u{2ceb}', '\u{2ceb}'), ('\u{2ced}', '\u{2ced}'), ('\u{2cf2}', '\u{2cf2}'), ('\u{a640}', - '\u{a640}'), ('\u{a642}', '\u{a642}'), ('\u{a644}', '\u{a644}'), ('\u{a646}', '\u{a646}'), - ('\u{a648}', '\u{a648}'), ('\u{a64a}', '\u{a64a}'), ('\u{a64c}', '\u{a64c}'), ('\u{a64e}', - '\u{a64e}'), ('\u{a650}', '\u{a650}'), ('\u{a652}', '\u{a652}'), ('\u{a654}', '\u{a654}'), - ('\u{a656}', '\u{a656}'), ('\u{a658}', '\u{a658}'), ('\u{a65a}', '\u{a65a}'), ('\u{a65c}', - '\u{a65c}'), ('\u{a65e}', '\u{a65e}'), ('\u{a660}', '\u{a660}'), ('\u{a662}', '\u{a662}'), - ('\u{a664}', '\u{a664}'), ('\u{a666}', '\u{a666}'), ('\u{a668}', '\u{a668}'), ('\u{a66a}', - '\u{a66a}'), ('\u{a66c}', '\u{a66c}'), ('\u{a680}', '\u{a680}'), ('\u{a682}', '\u{a682}'), - ('\u{a684}', '\u{a684}'), ('\u{a686}', '\u{a686}'), ('\u{a688}', '\u{a688}'), ('\u{a68a}', - '\u{a68a}'), ('\u{a68c}', '\u{a68c}'), ('\u{a68e}', '\u{a68e}'), ('\u{a690}', '\u{a690}'), - ('\u{a692}', '\u{a692}'), ('\u{a694}', '\u{a694}'), ('\u{a696}', '\u{a696}'), ('\u{a698}', - '\u{a698}'), ('\u{a69a}', '\u{a69a}'), ('\u{a722}', '\u{a722}'), ('\u{a724}', '\u{a724}'), - ('\u{a726}', '\u{a726}'), ('\u{a728}', '\u{a728}'), ('\u{a72a}', '\u{a72a}'), ('\u{a72c}', - '\u{a72c}'), ('\u{a72e}', '\u{a72e}'), ('\u{a732}', '\u{a732}'), ('\u{a734}', '\u{a734}'), - ('\u{a736}', '\u{a736}'), ('\u{a738}', '\u{a738}'), ('\u{a73a}', '\u{a73a}'), ('\u{a73c}', - '\u{a73c}'), ('\u{a73e}', '\u{a73e}'), ('\u{a740}', '\u{a740}'), ('\u{a742}', '\u{a742}'), - ('\u{a744}', '\u{a744}'), ('\u{a746}', '\u{a746}'), ('\u{a748}', '\u{a748}'), ('\u{a74a}', - '\u{a74a}'), ('\u{a74c}', '\u{a74c}'), ('\u{a74e}', '\u{a74e}'), ('\u{a750}', '\u{a750}'), - ('\u{a752}', '\u{a752}'), ('\u{a754}', '\u{a754}'), ('\u{a756}', '\u{a756}'), ('\u{a758}', - '\u{a758}'), ('\u{a75a}', '\u{a75a}'), ('\u{a75c}', '\u{a75c}'), ('\u{a75e}', '\u{a75e}'), - ('\u{a760}', '\u{a760}'), ('\u{a762}', '\u{a762}'), ('\u{a764}', '\u{a764}'), ('\u{a766}', - '\u{a766}'), ('\u{a768}', '\u{a768}'), ('\u{a76a}', '\u{a76a}'), ('\u{a76c}', '\u{a76c}'), - ('\u{a76e}', '\u{a76e}'), ('\u{a779}', '\u{a779}'), ('\u{a77b}', '\u{a77b}'), ('\u{a77d}', - '\u{a77e}'), ('\u{a780}', '\u{a780}'), ('\u{a782}', '\u{a782}'), ('\u{a784}', '\u{a784}'), - ('\u{a786}', '\u{a786}'), ('\u{a78b}', '\u{a78b}'), ('\u{a78d}', '\u{a78d}'), ('\u{a790}', - '\u{a790}'), ('\u{a792}', '\u{a792}'), ('\u{a796}', '\u{a796}'), ('\u{a798}', '\u{a798}'), - ('\u{a79a}', '\u{a79a}'), ('\u{a79c}', '\u{a79c}'), ('\u{a79e}', '\u{a79e}'), ('\u{a7a0}', - '\u{a7a0}'), ('\u{a7a2}', '\u{a7a2}'), ('\u{a7a4}', '\u{a7a4}'), ('\u{a7a6}', '\u{a7a6}'), - ('\u{a7a8}', '\u{a7a8}'), ('\u{a7aa}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b1}'), ('\u{ff21}', - '\u{ff3a}'), ('\u{10400}', '\u{10427}'), ('\u{118a0}', '\u{118bf}'), ('\u{1d400}', - '\u{1d419}'), ('\u{1d434}', '\u{1d44d}'), ('\u{1d468}', '\u{1d481}'), ('\u{1d49c}', - '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', - '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b5}'), ('\u{1d4d0}', - '\u{1d4e9}'), ('\u{1d504}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', - '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d538}', '\u{1d539}'), ('\u{1d53b}', - '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', - '\u{1d550}'), ('\u{1d56c}', '\u{1d585}'), ('\u{1d5a0}', '\u{1d5b9}'), ('\u{1d5d4}', - '\u{1d5ed}'), ('\u{1d608}', '\u{1d621}'), ('\u{1d63c}', '\u{1d655}'), ('\u{1d670}', - '\u{1d689}'), ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6e2}', '\u{1d6fa}'), ('\u{1d71c}', - '\u{1d734}'), ('\u{1d756}', '\u{1d76e}'), ('\u{1d790}', '\u{1d7a8}'), ('\u{1d7ca}', - '\u{1d7ca}') - ]; - - pub const M_table: &'static [(char, char)] = &[ - ('\u{300}', '\u{36f}'), ('\u{483}', '\u{489}'), ('\u{591}', '\u{5bd}'), ('\u{5bf}', - '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), - ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), ('\u{670}', '\u{670}'), ('\u{6d6}', - '\u{6dc}'), ('\u{6df}', '\u{6e4}'), ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), - ('\u{711}', '\u{711}'), ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', - '\u{7f3}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), ('\u{825}', '\u{827}'), - ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), ('\u{8e4}', '\u{903}'), ('\u{93a}', - '\u{93c}'), ('\u{93e}', '\u{94f}'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), - ('\u{981}', '\u{983}'), ('\u{9bc}', '\u{9bc}'), ('\u{9be}', '\u{9c4}'), ('\u{9c7}', - '\u{9c8}'), ('\u{9cb}', '\u{9cd}'), ('\u{9d7}', '\u{9d7}'), ('\u{9e2}', '\u{9e3}'), - ('\u{a01}', '\u{a03}'), ('\u{a3c}', '\u{a3c}'), ('\u{a3e}', '\u{a42}'), ('\u{a47}', - '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), - ('\u{a75}', '\u{a75}'), ('\u{a81}', '\u{a83}'), ('\u{abc}', '\u{abc}'), ('\u{abe}', - '\u{ac5}'), ('\u{ac7}', '\u{ac9}'), ('\u{acb}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), - ('\u{b01}', '\u{b03}'), ('\u{b3c}', '\u{b3c}'), ('\u{b3e}', '\u{b44}'), ('\u{b47}', - '\u{b48}'), ('\u{b4b}', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b62}', '\u{b63}'), - ('\u{b82}', '\u{b82}'), ('\u{bbe}', '\u{bc2}'), ('\u{bc6}', '\u{bc8}'), ('\u{bca}', - '\u{bcd}'), ('\u{bd7}', '\u{bd7}'), ('\u{c00}', '\u{c03}'), ('\u{c3e}', '\u{c44}'), - ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c62}', - '\u{c63}'), ('\u{c81}', '\u{c83}'), ('\u{cbc}', '\u{cbc}'), ('\u{cbe}', '\u{cc4}'), - ('\u{cc6}', '\u{cc8}'), ('\u{cca}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{ce2}', - '\u{ce3}'), ('\u{d01}', '\u{d03}'), ('\u{d3e}', '\u{d44}'), ('\u{d46}', '\u{d48}'), - ('\u{d4a}', '\u{d4d}'), ('\u{d57}', '\u{d57}'), ('\u{d62}', '\u{d63}'), ('\u{d82}', - '\u{d83}'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), - ('\u{dd8}', '\u{ddf}'), ('\u{df2}', '\u{df3}'), ('\u{e31}', '\u{e31}'), ('\u{e34}', - '\u{e3a}'), ('\u{e47}', '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), - ('\u{ebb}', '\u{ebc}'), ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', - '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f3e}', '\u{f3f}'), - ('\u{f71}', '\u{f84}'), ('\u{f86}', '\u{f87}'), ('\u{f8d}', '\u{f97}'), ('\u{f99}', - '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), ('\u{102b}', '\u{103e}'), ('\u{1056}', '\u{1059}'), - ('\u{105e}', '\u{1060}'), ('\u{1062}', '\u{1064}'), ('\u{1067}', '\u{106d}'), ('\u{1071}', - '\u{1074}'), ('\u{1082}', '\u{108d}'), ('\u{108f}', '\u{108f}'), ('\u{109a}', '\u{109d}'), - ('\u{135d}', '\u{135f}'), ('\u{1712}', '\u{1714}'), ('\u{1732}', '\u{1734}'), ('\u{1752}', - '\u{1753}'), ('\u{1772}', '\u{1773}'), ('\u{17b4}', '\u{17d3}'), ('\u{17dd}', '\u{17dd}'), - ('\u{180b}', '\u{180d}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', '\u{192b}'), ('\u{1930}', - '\u{193b}'), ('\u{19b0}', '\u{19c0}'), ('\u{19c8}', '\u{19c9}'), ('\u{1a17}', '\u{1a1b}'), - ('\u{1a55}', '\u{1a5e}'), ('\u{1a60}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), ('\u{1ab0}', - '\u{1abe}'), ('\u{1b00}', '\u{1b04}'), ('\u{1b34}', '\u{1b44}'), ('\u{1b6b}', '\u{1b73}'), - ('\u{1b80}', '\u{1b82}'), ('\u{1ba1}', '\u{1bad}'), ('\u{1be6}', '\u{1bf3}'), ('\u{1c24}', - '\u{1c37}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), - ('\u{1cf2}', '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), ('\u{1dc0}', '\u{1df5}'), ('\u{1dfc}', - '\u{1dff}'), ('\u{20d0}', '\u{20f0}'), ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), - ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302f}'), ('\u{3099}', '\u{309a}'), ('\u{a66f}', - '\u{a672}'), ('\u{a674}', '\u{a67d}'), ('\u{a69f}', '\u{a69f}'), ('\u{a6f0}', '\u{a6f1}'), - ('\u{a802}', '\u{a802}'), ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), ('\u{a823}', - '\u{a827}'), ('\u{a880}', '\u{a881}'), ('\u{a8b4}', '\u{a8c4}'), ('\u{a8e0}', '\u{a8f1}'), - ('\u{a926}', '\u{a92d}'), ('\u{a947}', '\u{a953}'), ('\u{a980}', '\u{a983}'), ('\u{a9b3}', - '\u{a9c0}'), ('\u{a9e5}', '\u{a9e5}'), ('\u{aa29}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), - ('\u{aa4c}', '\u{aa4d}'), ('\u{aa7b}', '\u{aa7d}'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', - '\u{aab4}'), ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'), - ('\u{aaeb}', '\u{aaef}'), ('\u{aaf5}', '\u{aaf6}'), ('\u{abe3}', '\u{abea}'), ('\u{abec}', - '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', '\u{fe2d}'), - ('\u{101fd}', '\u{101fd}'), ('\u{102e0}', '\u{102e0}'), ('\u{10376}', '\u{1037a}'), - ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '\u{10a0f}'), - ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', '\u{10ae6}'), - ('\u{11000}', '\u{11002}'), ('\u{11038}', '\u{11046}'), ('\u{1107f}', '\u{11082}'), - ('\u{110b0}', '\u{110ba}'), ('\u{11100}', '\u{11102}'), ('\u{11127}', '\u{11134}'), - ('\u{11173}', '\u{11173}'), ('\u{11180}', '\u{11182}'), ('\u{111b3}', '\u{111c0}'), - ('\u{1122c}', '\u{11237}'), ('\u{112df}', '\u{112ea}'), ('\u{11301}', '\u{11303}'), - ('\u{1133c}', '\u{1133c}'), ('\u{1133e}', '\u{11344}'), ('\u{11347}', '\u{11348}'), - ('\u{1134b}', '\u{1134d}'), ('\u{11357}', '\u{11357}'), ('\u{11362}', '\u{11363}'), - ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}'), ('\u{114b0}', '\u{114c3}'), - ('\u{115af}', '\u{115b5}'), ('\u{115b8}', '\u{115c0}'), ('\u{11630}', '\u{11640}'), - ('\u{116ab}', '\u{116b7}'), ('\u{16af0}', '\u{16af4}'), ('\u{16b30}', '\u{16b36}'), - ('\u{16f51}', '\u{16f7e}'), ('\u{16f8f}', '\u{16f92}'), ('\u{1bc9d}', '\u{1bc9e}'), - ('\u{1d165}', '\u{1d169}'), ('\u{1d16d}', '\u{1d172}'), ('\u{1d17b}', '\u{1d182}'), - ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), - ('\u{1e8d0}', '\u{1e8d6}'), ('\u{e0100}', '\u{e01ef}') - ]; - - pub const Mc_table: &'static [(char, char)] = &[ - ('\u{903}', '\u{903}'), ('\u{93b}', '\u{93b}'), ('\u{93e}', '\u{940}'), ('\u{949}', - '\u{94c}'), ('\u{94e}', '\u{94f}'), ('\u{982}', '\u{983}'), ('\u{9be}', '\u{9c0}'), - ('\u{9c7}', '\u{9c8}'), ('\u{9cb}', '\u{9cc}'), ('\u{9d7}', '\u{9d7}'), ('\u{a03}', - '\u{a03}'), ('\u{a3e}', '\u{a40}'), ('\u{a83}', '\u{a83}'), ('\u{abe}', '\u{ac0}'), - ('\u{ac9}', '\u{ac9}'), ('\u{acb}', '\u{acc}'), ('\u{b02}', '\u{b03}'), ('\u{b3e}', - '\u{b3e}'), ('\u{b40}', '\u{b40}'), ('\u{b47}', '\u{b48}'), ('\u{b4b}', '\u{b4c}'), - ('\u{b57}', '\u{b57}'), ('\u{bbe}', '\u{bbf}'), ('\u{bc1}', '\u{bc2}'), ('\u{bc6}', - '\u{bc8}'), ('\u{bca}', '\u{bcc}'), ('\u{bd7}', '\u{bd7}'), ('\u{c01}', '\u{c03}'), - ('\u{c41}', '\u{c44}'), ('\u{c82}', '\u{c83}'), ('\u{cbe}', '\u{cbe}'), ('\u{cc0}', - '\u{cc4}'), ('\u{cc7}', '\u{cc8}'), ('\u{cca}', '\u{ccb}'), ('\u{cd5}', '\u{cd6}'), - ('\u{d02}', '\u{d03}'), ('\u{d3e}', '\u{d40}'), ('\u{d46}', '\u{d48}'), ('\u{d4a}', - '\u{d4c}'), ('\u{d57}', '\u{d57}'), ('\u{d82}', '\u{d83}'), ('\u{dcf}', '\u{dd1}'), - ('\u{dd8}', '\u{ddf}'), ('\u{df2}', '\u{df3}'), ('\u{f3e}', '\u{f3f}'), ('\u{f7f}', - '\u{f7f}'), ('\u{102b}', '\u{102c}'), ('\u{1031}', '\u{1031}'), ('\u{1038}', '\u{1038}'), - ('\u{103b}', '\u{103c}'), ('\u{1056}', '\u{1057}'), ('\u{1062}', '\u{1064}'), ('\u{1067}', - '\u{106d}'), ('\u{1083}', '\u{1084}'), ('\u{1087}', '\u{108c}'), ('\u{108f}', '\u{108f}'), - ('\u{109a}', '\u{109c}'), ('\u{17b6}', '\u{17b6}'), ('\u{17be}', '\u{17c5}'), ('\u{17c7}', - '\u{17c8}'), ('\u{1923}', '\u{1926}'), ('\u{1929}', '\u{192b}'), ('\u{1930}', '\u{1931}'), - ('\u{1933}', '\u{1938}'), ('\u{19b0}', '\u{19c0}'), ('\u{19c8}', '\u{19c9}'), ('\u{1a19}', - '\u{1a1a}'), ('\u{1a55}', '\u{1a55}'), ('\u{1a57}', '\u{1a57}'), ('\u{1a61}', '\u{1a61}'), - ('\u{1a63}', '\u{1a64}'), ('\u{1a6d}', '\u{1a72}'), ('\u{1b04}', '\u{1b04}'), ('\u{1b35}', - '\u{1b35}'), ('\u{1b3b}', '\u{1b3b}'), ('\u{1b3d}', '\u{1b41}'), ('\u{1b43}', '\u{1b44}'), - ('\u{1b82}', '\u{1b82}'), ('\u{1ba1}', '\u{1ba1}'), ('\u{1ba6}', '\u{1ba7}'), ('\u{1baa}', - '\u{1baa}'), ('\u{1be7}', '\u{1be7}'), ('\u{1bea}', '\u{1bec}'), ('\u{1bee}', '\u{1bee}'), - ('\u{1bf2}', '\u{1bf3}'), ('\u{1c24}', '\u{1c2b}'), ('\u{1c34}', '\u{1c35}'), ('\u{1ce1}', - '\u{1ce1}'), ('\u{1cf2}', '\u{1cf3}'), ('\u{302e}', '\u{302f}'), ('\u{a823}', '\u{a824}'), - ('\u{a827}', '\u{a827}'), ('\u{a880}', '\u{a881}'), ('\u{a8b4}', '\u{a8c3}'), ('\u{a952}', - '\u{a953}'), ('\u{a983}', '\u{a983}'), ('\u{a9b4}', '\u{a9b5}'), ('\u{a9ba}', '\u{a9bb}'), - ('\u{a9bd}', '\u{a9c0}'), ('\u{aa2f}', '\u{aa30}'), ('\u{aa33}', '\u{aa34}'), ('\u{aa4d}', - '\u{aa4d}'), ('\u{aa7b}', '\u{aa7b}'), ('\u{aa7d}', '\u{aa7d}'), ('\u{aaeb}', '\u{aaeb}'), - ('\u{aaee}', '\u{aaef}'), ('\u{aaf5}', '\u{aaf5}'), ('\u{abe3}', '\u{abe4}'), ('\u{abe6}', - '\u{abe7}'), ('\u{abe9}', '\u{abea}'), ('\u{abec}', '\u{abec}'), ('\u{11000}', '\u{11000}'), - ('\u{11002}', '\u{11002}'), ('\u{11082}', '\u{11082}'), ('\u{110b0}', '\u{110b2}'), - ('\u{110b7}', '\u{110b8}'), ('\u{1112c}', '\u{1112c}'), ('\u{11182}', '\u{11182}'), - ('\u{111b3}', '\u{111b5}'), ('\u{111bf}', '\u{111c0}'), ('\u{1122c}', '\u{1122e}'), - ('\u{11232}', '\u{11233}'), ('\u{11235}', '\u{11235}'), ('\u{112e0}', '\u{112e2}'), - ('\u{11302}', '\u{11303}'), ('\u{1133e}', '\u{1133f}'), ('\u{11341}', '\u{11344}'), - ('\u{11347}', '\u{11348}'), ('\u{1134b}', '\u{1134d}'), ('\u{11357}', '\u{11357}'), - ('\u{11362}', '\u{11363}'), ('\u{114b0}', '\u{114b2}'), ('\u{114b9}', '\u{114b9}'), - ('\u{114bb}', '\u{114be}'), ('\u{114c1}', '\u{114c1}'), ('\u{115af}', '\u{115b1}'), - ('\u{115b8}', '\u{115bb}'), ('\u{115be}', '\u{115be}'), ('\u{11630}', '\u{11632}'), - ('\u{1163b}', '\u{1163c}'), ('\u{1163e}', '\u{1163e}'), ('\u{116ac}', '\u{116ac}'), - ('\u{116ae}', '\u{116af}'), ('\u{116b6}', '\u{116b6}'), ('\u{16f51}', '\u{16f7e}'), - ('\u{1d165}', '\u{1d166}'), ('\u{1d16d}', '\u{1d172}') - ]; - - pub const Me_table: &'static [(char, char)] = &[ - ('\u{488}', '\u{489}'), ('\u{1abe}', '\u{1abe}'), ('\u{20dd}', '\u{20e0}'), ('\u{20e2}', - '\u{20e4}'), ('\u{a670}', '\u{a672}') - ]; - - pub const Mn_table: &'static [(char, char)] = &[ - ('\u{300}', '\u{36f}'), ('\u{483}', '\u{487}'), ('\u{591}', '\u{5bd}'), ('\u{5bf}', - '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), - ('\u{610}', '\u{61a}'), ('\u{64b}', '\u{65f}'), ('\u{670}', '\u{670}'), ('\u{6d6}', - '\u{6dc}'), ('\u{6df}', '\u{6e4}'), ('\u{6e7}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), - ('\u{711}', '\u{711}'), ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}', - '\u{7f3}'), ('\u{816}', '\u{819}'), ('\u{81b}', '\u{823}'), ('\u{825}', '\u{827}'), - ('\u{829}', '\u{82d}'), ('\u{859}', '\u{85b}'), ('\u{8e4}', '\u{902}'), ('\u{93a}', - '\u{93a}'), ('\u{93c}', '\u{93c}'), ('\u{941}', '\u{948}'), ('\u{94d}', '\u{94d}'), - ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'), ('\u{981}', '\u{981}'), ('\u{9bc}', - '\u{9bc}'), ('\u{9c1}', '\u{9c4}'), ('\u{9cd}', '\u{9cd}'), ('\u{9e2}', '\u{9e3}'), - ('\u{a01}', '\u{a02}'), ('\u{a3c}', '\u{a3c}'), ('\u{a41}', '\u{a42}'), ('\u{a47}', - '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), - ('\u{a75}', '\u{a75}'), ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', - '\u{ac5}'), ('\u{ac7}', '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), - ('\u{b01}', '\u{b01}'), ('\u{b3c}', '\u{b3c}'), ('\u{b3f}', '\u{b3f}'), ('\u{b41}', - '\u{b44}'), ('\u{b4d}', '\u{b4d}'), ('\u{b56}', '\u{b56}'), ('\u{b62}', '\u{b63}'), - ('\u{b82}', '\u{b82}'), ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), ('\u{c00}', - '\u{c00}'), ('\u{c3e}', '\u{c40}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), - ('\u{c55}', '\u{c56}'), ('\u{c62}', '\u{c63}'), ('\u{c81}', '\u{c81}'), ('\u{cbc}', - '\u{cbc}'), ('\u{cbf}', '\u{cbf}'), ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), - ('\u{ce2}', '\u{ce3}'), ('\u{d01}', '\u{d01}'), ('\u{d41}', '\u{d44}'), ('\u{d4d}', - '\u{d4d}'), ('\u{d62}', '\u{d63}'), ('\u{dca}', '\u{dca}'), ('\u{dd2}', '\u{dd4}'), - ('\u{dd6}', '\u{dd6}'), ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), ('\u{e47}', - '\u{e4e}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), ('\u{ebb}', '\u{ebc}'), - ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', '\u{f35}'), ('\u{f37}', - '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f71}', '\u{f7e}'), ('\u{f80}', '\u{f84}'), - ('\u{f86}', '\u{f87}'), ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', - '\u{fc6}'), ('\u{102d}', '\u{1030}'), ('\u{1032}', '\u{1037}'), ('\u{1039}', '\u{103a}'), - ('\u{103d}', '\u{103e}'), ('\u{1058}', '\u{1059}'), ('\u{105e}', '\u{1060}'), ('\u{1071}', - '\u{1074}'), ('\u{1082}', '\u{1082}'), ('\u{1085}', '\u{1086}'), ('\u{108d}', '\u{108d}'), - ('\u{109d}', '\u{109d}'), ('\u{135d}', '\u{135f}'), ('\u{1712}', '\u{1714}'), ('\u{1732}', - '\u{1734}'), ('\u{1752}', '\u{1753}'), ('\u{1772}', '\u{1773}'), ('\u{17b4}', '\u{17b5}'), - ('\u{17b7}', '\u{17bd}'), ('\u{17c6}', '\u{17c6}'), ('\u{17c9}', '\u{17d3}'), ('\u{17dd}', - '\u{17dd}'), ('\u{180b}', '\u{180d}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', '\u{1922}'), - ('\u{1927}', '\u{1928}'), ('\u{1932}', '\u{1932}'), ('\u{1939}', '\u{193b}'), ('\u{1a17}', - '\u{1a18}'), ('\u{1a1b}', '\u{1a1b}'), ('\u{1a56}', '\u{1a56}'), ('\u{1a58}', '\u{1a5e}'), - ('\u{1a60}', '\u{1a60}'), ('\u{1a62}', '\u{1a62}'), ('\u{1a65}', '\u{1a6c}'), ('\u{1a73}', - '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), ('\u{1ab0}', '\u{1abd}'), ('\u{1b00}', '\u{1b03}'), - ('\u{1b34}', '\u{1b34}'), ('\u{1b36}', '\u{1b3a}'), ('\u{1b3c}', '\u{1b3c}'), ('\u{1b42}', - '\u{1b42}'), ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1b81}'), ('\u{1ba2}', '\u{1ba5}'), - ('\u{1ba8}', '\u{1ba9}'), ('\u{1bab}', '\u{1bad}'), ('\u{1be6}', '\u{1be6}'), ('\u{1be8}', - '\u{1be9}'), ('\u{1bed}', '\u{1bed}'), ('\u{1bef}', '\u{1bf1}'), ('\u{1c2c}', '\u{1c33}'), - ('\u{1c36}', '\u{1c37}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1ce0}'), ('\u{1ce2}', - '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), ('\u{1cf4}', '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), - ('\u{1dc0}', '\u{1df5}'), ('\u{1dfc}', '\u{1dff}'), ('\u{20d0}', '\u{20dc}'), ('\u{20e1}', - '\u{20e1}'), ('\u{20e5}', '\u{20f0}'), ('\u{2cef}', '\u{2cf1}'), ('\u{2d7f}', '\u{2d7f}'), - ('\u{2de0}', '\u{2dff}'), ('\u{302a}', '\u{302d}'), ('\u{3099}', '\u{309a}'), ('\u{a66f}', - '\u{a66f}'), ('\u{a674}', '\u{a67d}'), ('\u{a69f}', '\u{a69f}'), ('\u{a6f0}', '\u{a6f1}'), - ('\u{a802}', '\u{a802}'), ('\u{a806}', '\u{a806}'), ('\u{a80b}', '\u{a80b}'), ('\u{a825}', - '\u{a826}'), ('\u{a8c4}', '\u{a8c4}'), ('\u{a8e0}', '\u{a8f1}'), ('\u{a926}', '\u{a92d}'), - ('\u{a947}', '\u{a951}'), ('\u{a980}', '\u{a982}'), ('\u{a9b3}', '\u{a9b3}'), ('\u{a9b6}', - '\u{a9b9}'), ('\u{a9bc}', '\u{a9bc}'), ('\u{a9e5}', '\u{a9e5}'), ('\u{aa29}', '\u{aa2e}'), - ('\u{aa31}', '\u{aa32}'), ('\u{aa35}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', - '\u{aa4c}'), ('\u{aa7c}', '\u{aa7c}'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}', '\u{aab4}'), - ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'), ('\u{aaec}', - '\u{aaed}'), ('\u{aaf6}', '\u{aaf6}'), ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'), - ('\u{abed}', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', - '\u{fe2d}'), ('\u{101fd}', '\u{101fd}'), ('\u{102e0}', '\u{102e0}'), ('\u{10376}', - '\u{1037a}'), ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', - '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}', - '\u{10ae6}'), ('\u{11001}', '\u{11001}'), ('\u{11038}', '\u{11046}'), ('\u{1107f}', - '\u{11081}'), ('\u{110b3}', '\u{110b6}'), ('\u{110b9}', '\u{110ba}'), ('\u{11100}', - '\u{11102}'), ('\u{11127}', '\u{1112b}'), ('\u{1112d}', '\u{11134}'), ('\u{11173}', - '\u{11173}'), ('\u{11180}', '\u{11181}'), ('\u{111b6}', '\u{111be}'), ('\u{1122f}', - '\u{11231}'), ('\u{11234}', '\u{11234}'), ('\u{11236}', '\u{11237}'), ('\u{112df}', - '\u{112df}'), ('\u{112e3}', '\u{112ea}'), ('\u{11301}', '\u{11301}'), ('\u{1133c}', - '\u{1133c}'), ('\u{11340}', '\u{11340}'), ('\u{11366}', '\u{1136c}'), ('\u{11370}', - '\u{11374}'), ('\u{114b3}', '\u{114b8}'), ('\u{114ba}', '\u{114ba}'), ('\u{114bf}', - '\u{114c0}'), ('\u{114c2}', '\u{114c3}'), ('\u{115b2}', '\u{115b5}'), ('\u{115bc}', - '\u{115bd}'), ('\u{115bf}', '\u{115c0}'), ('\u{11633}', '\u{1163a}'), ('\u{1163d}', - '\u{1163d}'), ('\u{1163f}', '\u{11640}'), ('\u{116ab}', '\u{116ab}'), ('\u{116ad}', - '\u{116ad}'), ('\u{116b0}', '\u{116b5}'), ('\u{116b7}', '\u{116b7}'), ('\u{16af0}', - '\u{16af4}'), ('\u{16b30}', '\u{16b36}'), ('\u{16f8f}', '\u{16f92}'), ('\u{1bc9d}', - '\u{1bc9e}'), ('\u{1d167}', '\u{1d169}'), ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', - '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), ('\u{1e8d0}', - '\u{1e8d6}'), ('\u{e0100}', '\u{e01ef}') - ]; - pub const N_table: &'static [(char, char)] = &[ ('\u{30}', '\u{39}'), ('\u{660}', '\u{669}'), ('\u{6f0}', '\u{6f9}'), ('\u{7c0}', '\u{7c9}'), ('\u{966}', '\u{96f}'), ('\u{9e6}', '\u{9ef}'), ('\u{a66}', '\u{a6f}'), @@ -1372,402 +61,7 @@ pub mod general_category { super::bsearch_range_table(c, N_table) } - pub const Nd_table: &'static [(char, char)] = &[ - ('\u{30}', '\u{39}'), ('\u{660}', '\u{669}'), ('\u{6f0}', '\u{6f9}'), ('\u{7c0}', - '\u{7c9}'), ('\u{966}', '\u{96f}'), ('\u{9e6}', '\u{9ef}'), ('\u{a66}', '\u{a6f}'), - ('\u{ae6}', '\u{aef}'), ('\u{b66}', '\u{b6f}'), ('\u{be6}', '\u{bef}'), ('\u{c66}', - '\u{c6f}'), ('\u{ce6}', '\u{cef}'), ('\u{d66}', '\u{d6f}'), ('\u{de6}', '\u{def}'), - ('\u{e50}', '\u{e59}'), ('\u{ed0}', '\u{ed9}'), ('\u{f20}', '\u{f29}'), ('\u{1040}', - '\u{1049}'), ('\u{1090}', '\u{1099}'), ('\u{17e0}', '\u{17e9}'), ('\u{1810}', '\u{1819}'), - ('\u{1946}', '\u{194f}'), ('\u{19d0}', '\u{19d9}'), ('\u{1a80}', '\u{1a89}'), ('\u{1a90}', - '\u{1a99}'), ('\u{1b50}', '\u{1b59}'), ('\u{1bb0}', '\u{1bb9}'), ('\u{1c40}', '\u{1c49}'), - ('\u{1c50}', '\u{1c59}'), ('\u{a620}', '\u{a629}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a900}', - '\u{a909}'), ('\u{a9d0}', '\u{a9d9}'), ('\u{a9f0}', '\u{a9f9}'), ('\u{aa50}', '\u{aa59}'), - ('\u{abf0}', '\u{abf9}'), ('\u{ff10}', '\u{ff19}'), ('\u{104a0}', '\u{104a9}'), - ('\u{11066}', '\u{1106f}'), ('\u{110f0}', '\u{110f9}'), ('\u{11136}', '\u{1113f}'), - ('\u{111d0}', '\u{111d9}'), ('\u{112f0}', '\u{112f9}'), ('\u{114d0}', '\u{114d9}'), - ('\u{11650}', '\u{11659}'), ('\u{116c0}', '\u{116c9}'), ('\u{118e0}', '\u{118e9}'), - ('\u{16a60}', '\u{16a69}'), ('\u{16b50}', '\u{16b59}'), ('\u{1d7ce}', '\u{1d7ff}') - ]; - - pub const Nl_table: &'static [(char, char)] = &[ - ('\u{16ee}', '\u{16f0}'), ('\u{2160}', '\u{2182}'), ('\u{2185}', '\u{2188}'), ('\u{3007}', - '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3038}', '\u{303a}'), ('\u{a6e6}', '\u{a6ef}'), - ('\u{10140}', '\u{10174}'), ('\u{10341}', '\u{10341}'), ('\u{1034a}', '\u{1034a}'), - ('\u{103d1}', '\u{103d5}'), ('\u{12400}', '\u{1246e}') - ]; - - pub const No_table: &'static [(char, char)] = &[ - ('\u{b2}', '\u{b3}'), ('\u{b9}', '\u{b9}'), ('\u{bc}', '\u{be}'), ('\u{9f4}', '\u{9f9}'), - ('\u{b72}', '\u{b77}'), ('\u{bf0}', '\u{bf2}'), ('\u{c78}', '\u{c7e}'), ('\u{d70}', - '\u{d75}'), ('\u{f2a}', '\u{f33}'), ('\u{1369}', '\u{137c}'), ('\u{17f0}', '\u{17f9}'), - ('\u{19da}', '\u{19da}'), ('\u{2070}', '\u{2070}'), ('\u{2074}', '\u{2079}'), ('\u{2080}', - '\u{2089}'), ('\u{2150}', '\u{215f}'), ('\u{2189}', '\u{2189}'), ('\u{2460}', '\u{249b}'), - ('\u{24ea}', '\u{24ff}'), ('\u{2776}', '\u{2793}'), ('\u{2cfd}', '\u{2cfd}'), ('\u{3192}', - '\u{3195}'), ('\u{3220}', '\u{3229}'), ('\u{3248}', '\u{324f}'), ('\u{3251}', '\u{325f}'), - ('\u{3280}', '\u{3289}'), ('\u{32b1}', '\u{32bf}'), ('\u{a830}', '\u{a835}'), ('\u{10107}', - '\u{10133}'), ('\u{10175}', '\u{10178}'), ('\u{1018a}', '\u{1018b}'), ('\u{102e1}', - '\u{102fb}'), ('\u{10320}', '\u{10323}'), ('\u{10858}', '\u{1085f}'), ('\u{10879}', - '\u{1087f}'), ('\u{108a7}', '\u{108af}'), ('\u{10916}', '\u{1091b}'), ('\u{10a40}', - '\u{10a47}'), ('\u{10a7d}', '\u{10a7e}'), ('\u{10a9d}', '\u{10a9f}'), ('\u{10aeb}', - '\u{10aef}'), ('\u{10b58}', '\u{10b5f}'), ('\u{10b78}', '\u{10b7f}'), ('\u{10ba9}', - '\u{10baf}'), ('\u{10e60}', '\u{10e7e}'), ('\u{11052}', '\u{11065}'), ('\u{111e1}', - '\u{111f4}'), ('\u{118ea}', '\u{118f2}'), ('\u{16b5b}', '\u{16b61}'), ('\u{1d360}', - '\u{1d371}'), ('\u{1e8c7}', '\u{1e8cf}'), ('\u{1f100}', '\u{1f10c}') - ]; - - pub const P_table: &'static [(char, char)] = &[ - ('\u{21}', '\u{23}'), ('\u{25}', '\u{2a}'), ('\u{2c}', '\u{2f}'), ('\u{3a}', '\u{3b}'), - ('\u{3f}', '\u{40}'), ('\u{5b}', '\u{5d}'), ('\u{5f}', '\u{5f}'), ('\u{7b}', '\u{7b}'), - ('\u{7d}', '\u{7d}'), ('\u{a1}', '\u{a1}'), ('\u{a7}', '\u{a7}'), ('\u{ab}', '\u{ab}'), - ('\u{b6}', '\u{b7}'), ('\u{bb}', '\u{bb}'), ('\u{bf}', '\u{bf}'), ('\u{37e}', '\u{37e}'), - ('\u{387}', '\u{387}'), ('\u{55a}', '\u{55f}'), ('\u{589}', '\u{58a}'), ('\u{5be}', - '\u{5be}'), ('\u{5c0}', '\u{5c0}'), ('\u{5c3}', '\u{5c3}'), ('\u{5c6}', '\u{5c6}'), - ('\u{5f3}', '\u{5f4}'), ('\u{609}', '\u{60a}'), ('\u{60c}', '\u{60d}'), ('\u{61b}', - '\u{61b}'), ('\u{61e}', '\u{61f}'), ('\u{66a}', '\u{66d}'), ('\u{6d4}', '\u{6d4}'), - ('\u{700}', '\u{70d}'), ('\u{7f7}', '\u{7f9}'), ('\u{830}', '\u{83e}'), ('\u{85e}', - '\u{85e}'), ('\u{964}', '\u{965}'), ('\u{970}', '\u{970}'), ('\u{af0}', '\u{af0}'), - ('\u{df4}', '\u{df4}'), ('\u{e4f}', '\u{e4f}'), ('\u{e5a}', '\u{e5b}'), ('\u{f04}', - '\u{f12}'), ('\u{f14}', '\u{f14}'), ('\u{f3a}', '\u{f3d}'), ('\u{f85}', '\u{f85}'), - ('\u{fd0}', '\u{fd4}'), ('\u{fd9}', '\u{fda}'), ('\u{104a}', '\u{104f}'), ('\u{10fb}', - '\u{10fb}'), ('\u{1360}', '\u{1368}'), ('\u{1400}', '\u{1400}'), ('\u{166d}', '\u{166e}'), - ('\u{169b}', '\u{169c}'), ('\u{16eb}', '\u{16ed}'), ('\u{1735}', '\u{1736}'), ('\u{17d4}', - '\u{17d6}'), ('\u{17d8}', '\u{17da}'), ('\u{1800}', '\u{180a}'), ('\u{1944}', '\u{1945}'), - ('\u{1a1e}', '\u{1a1f}'), ('\u{1aa0}', '\u{1aa6}'), ('\u{1aa8}', '\u{1aad}'), ('\u{1b5a}', - '\u{1b60}'), ('\u{1bfc}', '\u{1bff}'), ('\u{1c3b}', '\u{1c3f}'), ('\u{1c7e}', '\u{1c7f}'), - ('\u{1cc0}', '\u{1cc7}'), ('\u{1cd3}', '\u{1cd3}'), ('\u{2010}', '\u{2027}'), ('\u{2030}', - '\u{2043}'), ('\u{2045}', '\u{2051}'), ('\u{2053}', '\u{205e}'), ('\u{207d}', '\u{207e}'), - ('\u{208d}', '\u{208e}'), ('\u{2308}', '\u{230b}'), ('\u{2329}', '\u{232a}'), ('\u{2768}', - '\u{2775}'), ('\u{27c5}', '\u{27c6}'), ('\u{27e6}', '\u{27ef}'), ('\u{2983}', '\u{2998}'), - ('\u{29d8}', '\u{29db}'), ('\u{29fc}', '\u{29fd}'), ('\u{2cf9}', '\u{2cfc}'), ('\u{2cfe}', - '\u{2cff}'), ('\u{2d70}', '\u{2d70}'), ('\u{2e00}', '\u{2e2e}'), ('\u{2e30}', '\u{2e42}'), - ('\u{3001}', '\u{3003}'), ('\u{3008}', '\u{3011}'), ('\u{3014}', '\u{301f}'), ('\u{3030}', - '\u{3030}'), ('\u{303d}', '\u{303d}'), ('\u{30a0}', '\u{30a0}'), ('\u{30fb}', '\u{30fb}'), - ('\u{a4fe}', '\u{a4ff}'), ('\u{a60d}', '\u{a60f}'), ('\u{a673}', '\u{a673}'), ('\u{a67e}', - '\u{a67e}'), ('\u{a6f2}', '\u{a6f7}'), ('\u{a874}', '\u{a877}'), ('\u{a8ce}', '\u{a8cf}'), - ('\u{a8f8}', '\u{a8fa}'), ('\u{a92e}', '\u{a92f}'), ('\u{a95f}', '\u{a95f}'), ('\u{a9c1}', - '\u{a9cd}'), ('\u{a9de}', '\u{a9df}'), ('\u{aa5c}', '\u{aa5f}'), ('\u{aade}', '\u{aadf}'), - ('\u{aaf0}', '\u{aaf1}'), ('\u{abeb}', '\u{abeb}'), ('\u{fd3e}', '\u{fd3f}'), ('\u{fe10}', - '\u{fe19}'), ('\u{fe30}', '\u{fe52}'), ('\u{fe54}', '\u{fe61}'), ('\u{fe63}', '\u{fe63}'), - ('\u{fe68}', '\u{fe68}'), ('\u{fe6a}', '\u{fe6b}'), ('\u{ff01}', '\u{ff03}'), ('\u{ff05}', - '\u{ff0a}'), ('\u{ff0c}', '\u{ff0f}'), ('\u{ff1a}', '\u{ff1b}'), ('\u{ff1f}', '\u{ff20}'), - ('\u{ff3b}', '\u{ff3d}'), ('\u{ff3f}', '\u{ff3f}'), ('\u{ff5b}', '\u{ff5b}'), ('\u{ff5d}', - '\u{ff5d}'), ('\u{ff5f}', '\u{ff65}'), ('\u{10100}', '\u{10102}'), ('\u{1039f}', - '\u{1039f}'), ('\u{103d0}', '\u{103d0}'), ('\u{1056f}', '\u{1056f}'), ('\u{10857}', - '\u{10857}'), ('\u{1091f}', '\u{1091f}'), ('\u{1093f}', '\u{1093f}'), ('\u{10a50}', - '\u{10a58}'), ('\u{10a7f}', '\u{10a7f}'), ('\u{10af0}', '\u{10af6}'), ('\u{10b39}', - '\u{10b3f}'), ('\u{10b99}', '\u{10b9c}'), ('\u{11047}', '\u{1104d}'), ('\u{110bb}', - '\u{110bc}'), ('\u{110be}', '\u{110c1}'), ('\u{11140}', '\u{11143}'), ('\u{11174}', - '\u{11175}'), ('\u{111c5}', '\u{111c8}'), ('\u{111cd}', '\u{111cd}'), ('\u{11238}', - '\u{1123d}'), ('\u{114c6}', '\u{114c6}'), ('\u{115c1}', '\u{115c9}'), ('\u{11641}', - '\u{11643}'), ('\u{12470}', '\u{12474}'), ('\u{16a6e}', '\u{16a6f}'), ('\u{16af5}', - '\u{16af5}'), ('\u{16b37}', '\u{16b3b}'), ('\u{16b44}', '\u{16b44}'), ('\u{1bc9f}', - '\u{1bc9f}') - ]; - - pub const Pc_table: &'static [(char, char)] = &[ - ('\u{5f}', '\u{5f}'), ('\u{203f}', '\u{2040}'), ('\u{2054}', '\u{2054}'), ('\u{fe33}', - '\u{fe34}'), ('\u{fe4d}', '\u{fe4f}'), ('\u{ff3f}', '\u{ff3f}') - ]; - - pub const Pd_table: &'static [(char, char)] = &[ - ('\u{2d}', '\u{2d}'), ('\u{58a}', '\u{58a}'), ('\u{5be}', '\u{5be}'), ('\u{1400}', - '\u{1400}'), ('\u{1806}', '\u{1806}'), ('\u{2010}', '\u{2015}'), ('\u{2e17}', '\u{2e17}'), - ('\u{2e1a}', '\u{2e1a}'), ('\u{2e3a}', '\u{2e3b}'), ('\u{2e40}', '\u{2e40}'), ('\u{301c}', - '\u{301c}'), ('\u{3030}', '\u{3030}'), ('\u{30a0}', '\u{30a0}'), ('\u{fe31}', '\u{fe32}'), - ('\u{fe58}', '\u{fe58}'), ('\u{fe63}', '\u{fe63}'), ('\u{ff0d}', '\u{ff0d}') - ]; - - pub const Pe_table: &'static [(char, char)] = &[ - ('\u{29}', '\u{29}'), ('\u{5d}', '\u{5d}'), ('\u{7d}', '\u{7d}'), ('\u{f3b}', '\u{f3b}'), - ('\u{f3d}', '\u{f3d}'), ('\u{169c}', '\u{169c}'), ('\u{2046}', '\u{2046}'), ('\u{207e}', - '\u{207e}'), ('\u{208e}', '\u{208e}'), ('\u{2309}', '\u{2309}'), ('\u{230b}', '\u{230b}'), - ('\u{232a}', '\u{232a}'), ('\u{2769}', '\u{2769}'), ('\u{276b}', '\u{276b}'), ('\u{276d}', - '\u{276d}'), ('\u{276f}', '\u{276f}'), ('\u{2771}', '\u{2771}'), ('\u{2773}', '\u{2773}'), - ('\u{2775}', '\u{2775}'), ('\u{27c6}', '\u{27c6}'), ('\u{27e7}', '\u{27e7}'), ('\u{27e9}', - '\u{27e9}'), ('\u{27eb}', '\u{27eb}'), ('\u{27ed}', '\u{27ed}'), ('\u{27ef}', '\u{27ef}'), - ('\u{2984}', '\u{2984}'), ('\u{2986}', '\u{2986}'), ('\u{2988}', '\u{2988}'), ('\u{298a}', - '\u{298a}'), ('\u{298c}', '\u{298c}'), ('\u{298e}', '\u{298e}'), ('\u{2990}', '\u{2990}'), - ('\u{2992}', '\u{2992}'), ('\u{2994}', '\u{2994}'), ('\u{2996}', '\u{2996}'), ('\u{2998}', - '\u{2998}'), ('\u{29d9}', '\u{29d9}'), ('\u{29db}', '\u{29db}'), ('\u{29fd}', '\u{29fd}'), - ('\u{2e23}', '\u{2e23}'), ('\u{2e25}', '\u{2e25}'), ('\u{2e27}', '\u{2e27}'), ('\u{2e29}', - '\u{2e29}'), ('\u{3009}', '\u{3009}'), ('\u{300b}', '\u{300b}'), ('\u{300d}', '\u{300d}'), - ('\u{300f}', '\u{300f}'), ('\u{3011}', '\u{3011}'), ('\u{3015}', '\u{3015}'), ('\u{3017}', - '\u{3017}'), ('\u{3019}', '\u{3019}'), ('\u{301b}', '\u{301b}'), ('\u{301e}', '\u{301f}'), - ('\u{fd3e}', '\u{fd3e}'), ('\u{fe18}', '\u{fe18}'), ('\u{fe36}', '\u{fe36}'), ('\u{fe38}', - '\u{fe38}'), ('\u{fe3a}', '\u{fe3a}'), ('\u{fe3c}', '\u{fe3c}'), ('\u{fe3e}', '\u{fe3e}'), - ('\u{fe40}', '\u{fe40}'), ('\u{fe42}', '\u{fe42}'), ('\u{fe44}', '\u{fe44}'), ('\u{fe48}', - '\u{fe48}'), ('\u{fe5a}', '\u{fe5a}'), ('\u{fe5c}', '\u{fe5c}'), ('\u{fe5e}', '\u{fe5e}'), - ('\u{ff09}', '\u{ff09}'), ('\u{ff3d}', '\u{ff3d}'), ('\u{ff5d}', '\u{ff5d}'), ('\u{ff60}', - '\u{ff60}'), ('\u{ff63}', '\u{ff63}') - ]; - - pub const Pf_table: &'static [(char, char)] = &[ - ('\u{bb}', '\u{bb}'), ('\u{2019}', '\u{2019}'), ('\u{201d}', '\u{201d}'), ('\u{203a}', - '\u{203a}'), ('\u{2e03}', '\u{2e03}'), ('\u{2e05}', '\u{2e05}'), ('\u{2e0a}', '\u{2e0a}'), - ('\u{2e0d}', '\u{2e0d}'), ('\u{2e1d}', '\u{2e1d}'), ('\u{2e21}', '\u{2e21}') - ]; - - pub const Pi_table: &'static [(char, char)] = &[ - ('\u{ab}', '\u{ab}'), ('\u{2018}', '\u{2018}'), ('\u{201b}', '\u{201c}'), ('\u{201f}', - '\u{201f}'), ('\u{2039}', '\u{2039}'), ('\u{2e02}', '\u{2e02}'), ('\u{2e04}', '\u{2e04}'), - ('\u{2e09}', '\u{2e09}'), ('\u{2e0c}', '\u{2e0c}'), ('\u{2e1c}', '\u{2e1c}'), ('\u{2e20}', - '\u{2e20}') - ]; - - pub const Po_table: &'static [(char, char)] = &[ - ('\u{21}', '\u{23}'), ('\u{25}', '\u{27}'), ('\u{2a}', '\u{2a}'), ('\u{2c}', '\u{2c}'), - ('\u{2e}', '\u{2f}'), ('\u{3a}', '\u{3b}'), ('\u{3f}', '\u{40}'), ('\u{5c}', '\u{5c}'), - ('\u{a1}', '\u{a1}'), ('\u{a7}', '\u{a7}'), ('\u{b6}', '\u{b7}'), ('\u{bf}', '\u{bf}'), - ('\u{37e}', '\u{37e}'), ('\u{387}', '\u{387}'), ('\u{55a}', '\u{55f}'), ('\u{589}', - '\u{589}'), ('\u{5c0}', '\u{5c0}'), ('\u{5c3}', '\u{5c3}'), ('\u{5c6}', '\u{5c6}'), - ('\u{5f3}', '\u{5f4}'), ('\u{609}', '\u{60a}'), ('\u{60c}', '\u{60d}'), ('\u{61b}', - '\u{61b}'), ('\u{61e}', '\u{61f}'), ('\u{66a}', '\u{66d}'), ('\u{6d4}', '\u{6d4}'), - ('\u{700}', '\u{70d}'), ('\u{7f7}', '\u{7f9}'), ('\u{830}', '\u{83e}'), ('\u{85e}', - '\u{85e}'), ('\u{964}', '\u{965}'), ('\u{970}', '\u{970}'), ('\u{af0}', '\u{af0}'), - ('\u{df4}', '\u{df4}'), ('\u{e4f}', '\u{e4f}'), ('\u{e5a}', '\u{e5b}'), ('\u{f04}', - '\u{f12}'), ('\u{f14}', '\u{f14}'), ('\u{f85}', '\u{f85}'), ('\u{fd0}', '\u{fd4}'), - ('\u{fd9}', '\u{fda}'), ('\u{104a}', '\u{104f}'), ('\u{10fb}', '\u{10fb}'), ('\u{1360}', - '\u{1368}'), ('\u{166d}', '\u{166e}'), ('\u{16eb}', '\u{16ed}'), ('\u{1735}', '\u{1736}'), - ('\u{17d4}', '\u{17d6}'), ('\u{17d8}', '\u{17da}'), ('\u{1800}', '\u{1805}'), ('\u{1807}', - '\u{180a}'), ('\u{1944}', '\u{1945}'), ('\u{1a1e}', '\u{1a1f}'), ('\u{1aa0}', '\u{1aa6}'), - ('\u{1aa8}', '\u{1aad}'), ('\u{1b5a}', '\u{1b60}'), ('\u{1bfc}', '\u{1bff}'), ('\u{1c3b}', - '\u{1c3f}'), ('\u{1c7e}', '\u{1c7f}'), ('\u{1cc0}', '\u{1cc7}'), ('\u{1cd3}', '\u{1cd3}'), - ('\u{2016}', '\u{2017}'), ('\u{2020}', '\u{2027}'), ('\u{2030}', '\u{2038}'), ('\u{203b}', - '\u{203e}'), ('\u{2041}', '\u{2043}'), ('\u{2047}', '\u{2051}'), ('\u{2053}', '\u{2053}'), - ('\u{2055}', '\u{205e}'), ('\u{2cf9}', '\u{2cfc}'), ('\u{2cfe}', '\u{2cff}'), ('\u{2d70}', - '\u{2d70}'), ('\u{2e00}', '\u{2e01}'), ('\u{2e06}', '\u{2e08}'), ('\u{2e0b}', '\u{2e0b}'), - ('\u{2e0e}', '\u{2e16}'), ('\u{2e18}', '\u{2e19}'), ('\u{2e1b}', '\u{2e1b}'), ('\u{2e1e}', - '\u{2e1f}'), ('\u{2e2a}', '\u{2e2e}'), ('\u{2e30}', '\u{2e39}'), ('\u{2e3c}', '\u{2e3f}'), - ('\u{2e41}', '\u{2e41}'), ('\u{3001}', '\u{3003}'), ('\u{303d}', '\u{303d}'), ('\u{30fb}', - '\u{30fb}'), ('\u{a4fe}', '\u{a4ff}'), ('\u{a60d}', '\u{a60f}'), ('\u{a673}', '\u{a673}'), - ('\u{a67e}', '\u{a67e}'), ('\u{a6f2}', '\u{a6f7}'), ('\u{a874}', '\u{a877}'), ('\u{a8ce}', - '\u{a8cf}'), ('\u{a8f8}', '\u{a8fa}'), ('\u{a92e}', '\u{a92f}'), ('\u{a95f}', '\u{a95f}'), - ('\u{a9c1}', '\u{a9cd}'), ('\u{a9de}', '\u{a9df}'), ('\u{aa5c}', '\u{aa5f}'), ('\u{aade}', - '\u{aadf}'), ('\u{aaf0}', '\u{aaf1}'), ('\u{abeb}', '\u{abeb}'), ('\u{fe10}', '\u{fe16}'), - ('\u{fe19}', '\u{fe19}'), ('\u{fe30}', '\u{fe30}'), ('\u{fe45}', '\u{fe46}'), ('\u{fe49}', - '\u{fe4c}'), ('\u{fe50}', '\u{fe52}'), ('\u{fe54}', '\u{fe57}'), ('\u{fe5f}', '\u{fe61}'), - ('\u{fe68}', '\u{fe68}'), ('\u{fe6a}', '\u{fe6b}'), ('\u{ff01}', '\u{ff03}'), ('\u{ff05}', - '\u{ff07}'), ('\u{ff0a}', '\u{ff0a}'), ('\u{ff0c}', '\u{ff0c}'), ('\u{ff0e}', '\u{ff0f}'), - ('\u{ff1a}', '\u{ff1b}'), ('\u{ff1f}', '\u{ff20}'), ('\u{ff3c}', '\u{ff3c}'), ('\u{ff61}', - '\u{ff61}'), ('\u{ff64}', '\u{ff65}'), ('\u{10100}', '\u{10102}'), ('\u{1039f}', - '\u{1039f}'), ('\u{103d0}', '\u{103d0}'), ('\u{1056f}', '\u{1056f}'), ('\u{10857}', - '\u{10857}'), ('\u{1091f}', '\u{1091f}'), ('\u{1093f}', '\u{1093f}'), ('\u{10a50}', - '\u{10a58}'), ('\u{10a7f}', '\u{10a7f}'), ('\u{10af0}', '\u{10af6}'), ('\u{10b39}', - '\u{10b3f}'), ('\u{10b99}', '\u{10b9c}'), ('\u{11047}', '\u{1104d}'), ('\u{110bb}', - '\u{110bc}'), ('\u{110be}', '\u{110c1}'), ('\u{11140}', '\u{11143}'), ('\u{11174}', - '\u{11175}'), ('\u{111c5}', '\u{111c8}'), ('\u{111cd}', '\u{111cd}'), ('\u{11238}', - '\u{1123d}'), ('\u{114c6}', '\u{114c6}'), ('\u{115c1}', '\u{115c9}'), ('\u{11641}', - '\u{11643}'), ('\u{12470}', '\u{12474}'), ('\u{16a6e}', '\u{16a6f}'), ('\u{16af5}', - '\u{16af5}'), ('\u{16b37}', '\u{16b3b}'), ('\u{16b44}', '\u{16b44}'), ('\u{1bc9f}', - '\u{1bc9f}') - ]; - - pub const Ps_table: &'static [(char, char)] = &[ - ('\u{28}', '\u{28}'), ('\u{5b}', '\u{5b}'), ('\u{7b}', '\u{7b}'), ('\u{f3a}', '\u{f3a}'), - ('\u{f3c}', '\u{f3c}'), ('\u{169b}', '\u{169b}'), ('\u{201a}', '\u{201a}'), ('\u{201e}', - '\u{201e}'), ('\u{2045}', '\u{2045}'), ('\u{207d}', '\u{207d}'), ('\u{208d}', '\u{208d}'), - ('\u{2308}', '\u{2308}'), ('\u{230a}', '\u{230a}'), ('\u{2329}', '\u{2329}'), ('\u{2768}', - '\u{2768}'), ('\u{276a}', '\u{276a}'), ('\u{276c}', '\u{276c}'), ('\u{276e}', '\u{276e}'), - ('\u{2770}', '\u{2770}'), ('\u{2772}', '\u{2772}'), ('\u{2774}', '\u{2774}'), ('\u{27c5}', - '\u{27c5}'), ('\u{27e6}', '\u{27e6}'), ('\u{27e8}', '\u{27e8}'), ('\u{27ea}', '\u{27ea}'), - ('\u{27ec}', '\u{27ec}'), ('\u{27ee}', '\u{27ee}'), ('\u{2983}', '\u{2983}'), ('\u{2985}', - '\u{2985}'), ('\u{2987}', '\u{2987}'), ('\u{2989}', '\u{2989}'), ('\u{298b}', '\u{298b}'), - ('\u{298d}', '\u{298d}'), ('\u{298f}', '\u{298f}'), ('\u{2991}', '\u{2991}'), ('\u{2993}', - '\u{2993}'), ('\u{2995}', '\u{2995}'), ('\u{2997}', '\u{2997}'), ('\u{29d8}', '\u{29d8}'), - ('\u{29da}', '\u{29da}'), ('\u{29fc}', '\u{29fc}'), ('\u{2e22}', '\u{2e22}'), ('\u{2e24}', - '\u{2e24}'), ('\u{2e26}', '\u{2e26}'), ('\u{2e28}', '\u{2e28}'), ('\u{2e42}', '\u{2e42}'), - ('\u{3008}', '\u{3008}'), ('\u{300a}', '\u{300a}'), ('\u{300c}', '\u{300c}'), ('\u{300e}', - '\u{300e}'), ('\u{3010}', '\u{3010}'), ('\u{3014}', '\u{3014}'), ('\u{3016}', '\u{3016}'), - ('\u{3018}', '\u{3018}'), ('\u{301a}', '\u{301a}'), ('\u{301d}', '\u{301d}'), ('\u{fd3f}', - '\u{fd3f}'), ('\u{fe17}', '\u{fe17}'), ('\u{fe35}', '\u{fe35}'), ('\u{fe37}', '\u{fe37}'), - ('\u{fe39}', '\u{fe39}'), ('\u{fe3b}', '\u{fe3b}'), ('\u{fe3d}', '\u{fe3d}'), ('\u{fe3f}', - '\u{fe3f}'), ('\u{fe41}', '\u{fe41}'), ('\u{fe43}', '\u{fe43}'), ('\u{fe47}', '\u{fe47}'), - ('\u{fe59}', '\u{fe59}'), ('\u{fe5b}', '\u{fe5b}'), ('\u{fe5d}', '\u{fe5d}'), ('\u{ff08}', - '\u{ff08}'), ('\u{ff3b}', '\u{ff3b}'), ('\u{ff5b}', '\u{ff5b}'), ('\u{ff5f}', '\u{ff5f}'), - ('\u{ff62}', '\u{ff62}') - ]; - - pub const S_table: &'static [(char, char)] = &[ - ('\u{24}', '\u{24}'), ('\u{2b}', '\u{2b}'), ('\u{3c}', '\u{3e}'), ('\u{5e}', '\u{5e}'), - ('\u{60}', '\u{60}'), ('\u{7c}', '\u{7c}'), ('\u{7e}', '\u{7e}'), ('\u{a2}', '\u{a6}'), - ('\u{a8}', '\u{a9}'), ('\u{ac}', '\u{ac}'), ('\u{ae}', '\u{b1}'), ('\u{b4}', '\u{b4}'), - ('\u{b8}', '\u{b8}'), ('\u{d7}', '\u{d7}'), ('\u{f7}', '\u{f7}'), ('\u{2c2}', '\u{2c5}'), - ('\u{2d2}', '\u{2df}'), ('\u{2e5}', '\u{2eb}'), ('\u{2ed}', '\u{2ed}'), ('\u{2ef}', - '\u{2ff}'), ('\u{375}', '\u{375}'), ('\u{384}', '\u{385}'), ('\u{3f6}', '\u{3f6}'), - ('\u{482}', '\u{482}'), ('\u{58d}', '\u{58f}'), ('\u{606}', '\u{608}'), ('\u{60b}', - '\u{60b}'), ('\u{60e}', '\u{60f}'), ('\u{6de}', '\u{6de}'), ('\u{6e9}', '\u{6e9}'), - ('\u{6fd}', '\u{6fe}'), ('\u{7f6}', '\u{7f6}'), ('\u{9f2}', '\u{9f3}'), ('\u{9fa}', - '\u{9fb}'), ('\u{af1}', '\u{af1}'), ('\u{b70}', '\u{b70}'), ('\u{bf3}', '\u{bfa}'), - ('\u{c7f}', '\u{c7f}'), ('\u{d79}', '\u{d79}'), ('\u{e3f}', '\u{e3f}'), ('\u{f01}', - '\u{f03}'), ('\u{f13}', '\u{f13}'), ('\u{f15}', '\u{f17}'), ('\u{f1a}', '\u{f1f}'), - ('\u{f34}', '\u{f34}'), ('\u{f36}', '\u{f36}'), ('\u{f38}', '\u{f38}'), ('\u{fbe}', - '\u{fc5}'), ('\u{fc7}', '\u{fcc}'), ('\u{fce}', '\u{fcf}'), ('\u{fd5}', '\u{fd8}'), - ('\u{109e}', '\u{109f}'), ('\u{1390}', '\u{1399}'), ('\u{17db}', '\u{17db}'), ('\u{1940}', - '\u{1940}'), ('\u{19de}', '\u{19ff}'), ('\u{1b61}', '\u{1b6a}'), ('\u{1b74}', '\u{1b7c}'), - ('\u{1fbd}', '\u{1fbd}'), ('\u{1fbf}', '\u{1fc1}'), ('\u{1fcd}', '\u{1fcf}'), ('\u{1fdd}', - '\u{1fdf}'), ('\u{1fed}', '\u{1fef}'), ('\u{1ffd}', '\u{1ffe}'), ('\u{2044}', '\u{2044}'), - ('\u{2052}', '\u{2052}'), ('\u{207a}', '\u{207c}'), ('\u{208a}', '\u{208c}'), ('\u{20a0}', - '\u{20bd}'), ('\u{2100}', '\u{2101}'), ('\u{2103}', '\u{2106}'), ('\u{2108}', '\u{2109}'), - ('\u{2114}', '\u{2114}'), ('\u{2116}', '\u{2118}'), ('\u{211e}', '\u{2123}'), ('\u{2125}', - '\u{2125}'), ('\u{2127}', '\u{2127}'), ('\u{2129}', '\u{2129}'), ('\u{212e}', '\u{212e}'), - ('\u{213a}', '\u{213b}'), ('\u{2140}', '\u{2144}'), ('\u{214a}', '\u{214d}'), ('\u{214f}', - '\u{214f}'), ('\u{2190}', '\u{2307}'), ('\u{230c}', '\u{2328}'), ('\u{232b}', '\u{23fa}'), - ('\u{2400}', '\u{2426}'), ('\u{2440}', '\u{244a}'), ('\u{249c}', '\u{24e9}'), ('\u{2500}', - '\u{2767}'), ('\u{2794}', '\u{27c4}'), ('\u{27c7}', '\u{27e5}'), ('\u{27f0}', '\u{2982}'), - ('\u{2999}', '\u{29d7}'), ('\u{29dc}', '\u{29fb}'), ('\u{29fe}', '\u{2b73}'), ('\u{2b76}', - '\u{2b95}'), ('\u{2b98}', '\u{2bb9}'), ('\u{2bbd}', '\u{2bc8}'), ('\u{2bca}', '\u{2bd1}'), - ('\u{2ce5}', '\u{2cea}'), ('\u{2e80}', '\u{2e99}'), ('\u{2e9b}', '\u{2ef3}'), ('\u{2f00}', - '\u{2fd5}'), ('\u{2ff0}', '\u{2ffb}'), ('\u{3004}', '\u{3004}'), ('\u{3012}', '\u{3013}'), - ('\u{3020}', '\u{3020}'), ('\u{3036}', '\u{3037}'), ('\u{303e}', '\u{303f}'), ('\u{309b}', - '\u{309c}'), ('\u{3190}', '\u{3191}'), ('\u{3196}', '\u{319f}'), ('\u{31c0}', '\u{31e3}'), - ('\u{3200}', '\u{321e}'), ('\u{322a}', '\u{3247}'), ('\u{3250}', '\u{3250}'), ('\u{3260}', - '\u{327f}'), ('\u{328a}', '\u{32b0}'), ('\u{32c0}', '\u{32fe}'), ('\u{3300}', '\u{33ff}'), - ('\u{4dc0}', '\u{4dff}'), ('\u{a490}', '\u{a4c6}'), ('\u{a700}', '\u{a716}'), ('\u{a720}', - '\u{a721}'), ('\u{a789}', '\u{a78a}'), ('\u{a828}', '\u{a82b}'), ('\u{a836}', '\u{a839}'), - ('\u{aa77}', '\u{aa79}'), ('\u{ab5b}', '\u{ab5b}'), ('\u{fb29}', '\u{fb29}'), ('\u{fbb2}', - '\u{fbc1}'), ('\u{fdfc}', '\u{fdfd}'), ('\u{fe62}', '\u{fe62}'), ('\u{fe64}', '\u{fe66}'), - ('\u{fe69}', '\u{fe69}'), ('\u{ff04}', '\u{ff04}'), ('\u{ff0b}', '\u{ff0b}'), ('\u{ff1c}', - '\u{ff1e}'), ('\u{ff3e}', '\u{ff3e}'), ('\u{ff40}', '\u{ff40}'), ('\u{ff5c}', '\u{ff5c}'), - ('\u{ff5e}', '\u{ff5e}'), ('\u{ffe0}', '\u{ffe6}'), ('\u{ffe8}', '\u{ffee}'), ('\u{fffc}', - '\u{fffd}'), ('\u{10137}', '\u{1013f}'), ('\u{10179}', '\u{10189}'), ('\u{1018c}', - '\u{1018c}'), ('\u{10190}', '\u{1019b}'), ('\u{101a0}', '\u{101a0}'), ('\u{101d0}', - '\u{101fc}'), ('\u{10877}', '\u{10878}'), ('\u{10ac8}', '\u{10ac8}'), ('\u{16b3c}', - '\u{16b3f}'), ('\u{16b45}', '\u{16b45}'), ('\u{1bc9c}', '\u{1bc9c}'), ('\u{1d000}', - '\u{1d0f5}'), ('\u{1d100}', '\u{1d126}'), ('\u{1d129}', '\u{1d164}'), ('\u{1d16a}', - '\u{1d16c}'), ('\u{1d183}', '\u{1d184}'), ('\u{1d18c}', '\u{1d1a9}'), ('\u{1d1ae}', - '\u{1d1dd}'), ('\u{1d200}', '\u{1d241}'), ('\u{1d245}', '\u{1d245}'), ('\u{1d300}', - '\u{1d356}'), ('\u{1d6c1}', '\u{1d6c1}'), ('\u{1d6db}', '\u{1d6db}'), ('\u{1d6fb}', - '\u{1d6fb}'), ('\u{1d715}', '\u{1d715}'), ('\u{1d735}', '\u{1d735}'), ('\u{1d74f}', - '\u{1d74f}'), ('\u{1d76f}', '\u{1d76f}'), ('\u{1d789}', '\u{1d789}'), ('\u{1d7a9}', - '\u{1d7a9}'), ('\u{1d7c3}', '\u{1d7c3}'), ('\u{1eef0}', '\u{1eef1}'), ('\u{1f000}', - '\u{1f02b}'), ('\u{1f030}', '\u{1f093}'), ('\u{1f0a0}', '\u{1f0ae}'), ('\u{1f0b1}', - '\u{1f0bf}'), ('\u{1f0c1}', '\u{1f0cf}'), ('\u{1f0d1}', '\u{1f0f5}'), ('\u{1f110}', - '\u{1f12e}'), ('\u{1f130}', '\u{1f16b}'), ('\u{1f170}', '\u{1f19a}'), ('\u{1f1e6}', - '\u{1f202}'), ('\u{1f210}', '\u{1f23a}'), ('\u{1f240}', '\u{1f248}'), ('\u{1f250}', - '\u{1f251}'), ('\u{1f300}', '\u{1f32c}'), ('\u{1f330}', '\u{1f37d}'), ('\u{1f380}', - '\u{1f3ce}'), ('\u{1f3d4}', '\u{1f3f7}'), ('\u{1f400}', '\u{1f4fe}'), ('\u{1f500}', - '\u{1f54a}'), ('\u{1f550}', '\u{1f579}'), ('\u{1f57b}', '\u{1f5a3}'), ('\u{1f5a5}', - '\u{1f642}'), ('\u{1f645}', '\u{1f6cf}'), ('\u{1f6e0}', '\u{1f6ec}'), ('\u{1f6f0}', - '\u{1f6f3}'), ('\u{1f700}', '\u{1f773}'), ('\u{1f780}', '\u{1f7d4}'), ('\u{1f800}', - '\u{1f80b}'), ('\u{1f810}', '\u{1f847}'), ('\u{1f850}', '\u{1f859}'), ('\u{1f860}', - '\u{1f887}'), ('\u{1f890}', '\u{1f8ad}') - ]; - - pub const Sc_table: &'static [(char, char)] = &[ - ('\u{24}', '\u{24}'), ('\u{a2}', '\u{a5}'), ('\u{58f}', '\u{58f}'), ('\u{60b}', '\u{60b}'), - ('\u{9f2}', '\u{9f3}'), ('\u{9fb}', '\u{9fb}'), ('\u{af1}', '\u{af1}'), ('\u{bf9}', - '\u{bf9}'), ('\u{e3f}', '\u{e3f}'), ('\u{17db}', '\u{17db}'), ('\u{20a0}', '\u{20bd}'), - ('\u{a838}', '\u{a838}'), ('\u{fdfc}', '\u{fdfc}'), ('\u{fe69}', '\u{fe69}'), ('\u{ff04}', - '\u{ff04}'), ('\u{ffe0}', '\u{ffe1}'), ('\u{ffe5}', '\u{ffe6}') - ]; - - pub const Sk_table: &'static [(char, char)] = &[ - ('\u{5e}', '\u{5e}'), ('\u{60}', '\u{60}'), ('\u{a8}', '\u{a8}'), ('\u{af}', '\u{af}'), - ('\u{b4}', '\u{b4}'), ('\u{b8}', '\u{b8}'), ('\u{2c2}', '\u{2c5}'), ('\u{2d2}', '\u{2df}'), - ('\u{2e5}', '\u{2eb}'), ('\u{2ed}', '\u{2ed}'), ('\u{2ef}', '\u{2ff}'), ('\u{375}', - '\u{375}'), ('\u{384}', '\u{385}'), ('\u{1fbd}', '\u{1fbd}'), ('\u{1fbf}', '\u{1fc1}'), - ('\u{1fcd}', '\u{1fcf}'), ('\u{1fdd}', '\u{1fdf}'), ('\u{1fed}', '\u{1fef}'), ('\u{1ffd}', - '\u{1ffe}'), ('\u{309b}', '\u{309c}'), ('\u{a700}', '\u{a716}'), ('\u{a720}', '\u{a721}'), - ('\u{a789}', '\u{a78a}'), ('\u{ab5b}', '\u{ab5b}'), ('\u{fbb2}', '\u{fbc1}'), ('\u{ff3e}', - '\u{ff3e}'), ('\u{ff40}', '\u{ff40}'), ('\u{ffe3}', '\u{ffe3}') - ]; - - pub const Sm_table: &'static [(char, char)] = &[ - ('\u{2b}', '\u{2b}'), ('\u{3c}', '\u{3e}'), ('\u{7c}', '\u{7c}'), ('\u{7e}', '\u{7e}'), - ('\u{ac}', '\u{ac}'), ('\u{b1}', '\u{b1}'), ('\u{d7}', '\u{d7}'), ('\u{f7}', '\u{f7}'), - ('\u{3f6}', '\u{3f6}'), ('\u{606}', '\u{608}'), ('\u{2044}', '\u{2044}'), ('\u{2052}', - '\u{2052}'), ('\u{207a}', '\u{207c}'), ('\u{208a}', '\u{208c}'), ('\u{2118}', '\u{2118}'), - ('\u{2140}', '\u{2144}'), ('\u{214b}', '\u{214b}'), ('\u{2190}', '\u{2194}'), ('\u{219a}', - '\u{219b}'), ('\u{21a0}', '\u{21a0}'), ('\u{21a3}', '\u{21a3}'), ('\u{21a6}', '\u{21a6}'), - ('\u{21ae}', '\u{21ae}'), ('\u{21ce}', '\u{21cf}'), ('\u{21d2}', '\u{21d2}'), ('\u{21d4}', - '\u{21d4}'), ('\u{21f4}', '\u{22ff}'), ('\u{2320}', '\u{2321}'), ('\u{237c}', '\u{237c}'), - ('\u{239b}', '\u{23b3}'), ('\u{23dc}', '\u{23e1}'), ('\u{25b7}', '\u{25b7}'), ('\u{25c1}', - '\u{25c1}'), ('\u{25f8}', '\u{25ff}'), ('\u{266f}', '\u{266f}'), ('\u{27c0}', '\u{27c4}'), - ('\u{27c7}', '\u{27e5}'), ('\u{27f0}', '\u{27ff}'), ('\u{2900}', '\u{2982}'), ('\u{2999}', - '\u{29d7}'), ('\u{29dc}', '\u{29fb}'), ('\u{29fe}', '\u{2aff}'), ('\u{2b30}', '\u{2b44}'), - ('\u{2b47}', '\u{2b4c}'), ('\u{fb29}', '\u{fb29}'), ('\u{fe62}', '\u{fe62}'), ('\u{fe64}', - '\u{fe66}'), ('\u{ff0b}', '\u{ff0b}'), ('\u{ff1c}', '\u{ff1e}'), ('\u{ff5c}', '\u{ff5c}'), - ('\u{ff5e}', '\u{ff5e}'), ('\u{ffe2}', '\u{ffe2}'), ('\u{ffe9}', '\u{ffec}'), ('\u{1d6c1}', - '\u{1d6c1}'), ('\u{1d6db}', '\u{1d6db}'), ('\u{1d6fb}', '\u{1d6fb}'), ('\u{1d715}', - '\u{1d715}'), ('\u{1d735}', '\u{1d735}'), ('\u{1d74f}', '\u{1d74f}'), ('\u{1d76f}', - '\u{1d76f}'), ('\u{1d789}', '\u{1d789}'), ('\u{1d7a9}', '\u{1d7a9}'), ('\u{1d7c3}', - '\u{1d7c3}'), ('\u{1eef0}', '\u{1eef1}') - ]; - - pub const So_table: &'static [(char, char)] = &[ - ('\u{a6}', '\u{a6}'), ('\u{a9}', '\u{a9}'), ('\u{ae}', '\u{ae}'), ('\u{b0}', '\u{b0}'), - ('\u{482}', '\u{482}'), ('\u{58d}', '\u{58e}'), ('\u{60e}', '\u{60f}'), ('\u{6de}', - '\u{6de}'), ('\u{6e9}', '\u{6e9}'), ('\u{6fd}', '\u{6fe}'), ('\u{7f6}', '\u{7f6}'), - ('\u{9fa}', '\u{9fa}'), ('\u{b70}', '\u{b70}'), ('\u{bf3}', '\u{bf8}'), ('\u{bfa}', - '\u{bfa}'), ('\u{c7f}', '\u{c7f}'), ('\u{d79}', '\u{d79}'), ('\u{f01}', '\u{f03}'), - ('\u{f13}', '\u{f13}'), ('\u{f15}', '\u{f17}'), ('\u{f1a}', '\u{f1f}'), ('\u{f34}', - '\u{f34}'), ('\u{f36}', '\u{f36}'), ('\u{f38}', '\u{f38}'), ('\u{fbe}', '\u{fc5}'), - ('\u{fc7}', '\u{fcc}'), ('\u{fce}', '\u{fcf}'), ('\u{fd5}', '\u{fd8}'), ('\u{109e}', - '\u{109f}'), ('\u{1390}', '\u{1399}'), ('\u{1940}', '\u{1940}'), ('\u{19de}', '\u{19ff}'), - ('\u{1b61}', '\u{1b6a}'), ('\u{1b74}', '\u{1b7c}'), ('\u{2100}', '\u{2101}'), ('\u{2103}', - '\u{2106}'), ('\u{2108}', '\u{2109}'), ('\u{2114}', '\u{2114}'), ('\u{2116}', '\u{2117}'), - ('\u{211e}', '\u{2123}'), ('\u{2125}', '\u{2125}'), ('\u{2127}', '\u{2127}'), ('\u{2129}', - '\u{2129}'), ('\u{212e}', '\u{212e}'), ('\u{213a}', '\u{213b}'), ('\u{214a}', '\u{214a}'), - ('\u{214c}', '\u{214d}'), ('\u{214f}', '\u{214f}'), ('\u{2195}', '\u{2199}'), ('\u{219c}', - '\u{219f}'), ('\u{21a1}', '\u{21a2}'), ('\u{21a4}', '\u{21a5}'), ('\u{21a7}', '\u{21ad}'), - ('\u{21af}', '\u{21cd}'), ('\u{21d0}', '\u{21d1}'), ('\u{21d3}', '\u{21d3}'), ('\u{21d5}', - '\u{21f3}'), ('\u{2300}', '\u{2307}'), ('\u{230c}', '\u{231f}'), ('\u{2322}', '\u{2328}'), - ('\u{232b}', '\u{237b}'), ('\u{237d}', '\u{239a}'), ('\u{23b4}', '\u{23db}'), ('\u{23e2}', - '\u{23fa}'), ('\u{2400}', '\u{2426}'), ('\u{2440}', '\u{244a}'), ('\u{249c}', '\u{24e9}'), - ('\u{2500}', '\u{25b6}'), ('\u{25b8}', '\u{25c0}'), ('\u{25c2}', '\u{25f7}'), ('\u{2600}', - '\u{266e}'), ('\u{2670}', '\u{2767}'), ('\u{2794}', '\u{27bf}'), ('\u{2800}', '\u{28ff}'), - ('\u{2b00}', '\u{2b2f}'), ('\u{2b45}', '\u{2b46}'), ('\u{2b4d}', '\u{2b73}'), ('\u{2b76}', - '\u{2b95}'), ('\u{2b98}', '\u{2bb9}'), ('\u{2bbd}', '\u{2bc8}'), ('\u{2bca}', '\u{2bd1}'), - ('\u{2ce5}', '\u{2cea}'), ('\u{2e80}', '\u{2e99}'), ('\u{2e9b}', '\u{2ef3}'), ('\u{2f00}', - '\u{2fd5}'), ('\u{2ff0}', '\u{2ffb}'), ('\u{3004}', '\u{3004}'), ('\u{3012}', '\u{3013}'), - ('\u{3020}', '\u{3020}'), ('\u{3036}', '\u{3037}'), ('\u{303e}', '\u{303f}'), ('\u{3190}', - '\u{3191}'), ('\u{3196}', '\u{319f}'), ('\u{31c0}', '\u{31e3}'), ('\u{3200}', '\u{321e}'), - ('\u{322a}', '\u{3247}'), ('\u{3250}', '\u{3250}'), ('\u{3260}', '\u{327f}'), ('\u{328a}', - '\u{32b0}'), ('\u{32c0}', '\u{32fe}'), ('\u{3300}', '\u{33ff}'), ('\u{4dc0}', '\u{4dff}'), - ('\u{a490}', '\u{a4c6}'), ('\u{a828}', '\u{a82b}'), ('\u{a836}', '\u{a837}'), ('\u{a839}', - '\u{a839}'), ('\u{aa77}', '\u{aa79}'), ('\u{fdfd}', '\u{fdfd}'), ('\u{ffe4}', '\u{ffe4}'), - ('\u{ffe8}', '\u{ffe8}'), ('\u{ffed}', '\u{ffee}'), ('\u{fffc}', '\u{fffd}'), ('\u{10137}', - '\u{1013f}'), ('\u{10179}', '\u{10189}'), ('\u{1018c}', '\u{1018c}'), ('\u{10190}', - '\u{1019b}'), ('\u{101a0}', '\u{101a0}'), ('\u{101d0}', '\u{101fc}'), ('\u{10877}', - '\u{10878}'), ('\u{10ac8}', '\u{10ac8}'), ('\u{16b3c}', '\u{16b3f}'), ('\u{16b45}', - '\u{16b45}'), ('\u{1bc9c}', '\u{1bc9c}'), ('\u{1d000}', '\u{1d0f5}'), ('\u{1d100}', - '\u{1d126}'), ('\u{1d129}', '\u{1d164}'), ('\u{1d16a}', '\u{1d16c}'), ('\u{1d183}', - '\u{1d184}'), ('\u{1d18c}', '\u{1d1a9}'), ('\u{1d1ae}', '\u{1d1dd}'), ('\u{1d200}', - '\u{1d241}'), ('\u{1d245}', '\u{1d245}'), ('\u{1d300}', '\u{1d356}'), ('\u{1f000}', - '\u{1f02b}'), ('\u{1f030}', '\u{1f093}'), ('\u{1f0a0}', '\u{1f0ae}'), ('\u{1f0b1}', - '\u{1f0bf}'), ('\u{1f0c1}', '\u{1f0cf}'), ('\u{1f0d1}', '\u{1f0f5}'), ('\u{1f110}', - '\u{1f12e}'), ('\u{1f130}', '\u{1f16b}'), ('\u{1f170}', '\u{1f19a}'), ('\u{1f1e6}', - '\u{1f202}'), ('\u{1f210}', '\u{1f23a}'), ('\u{1f240}', '\u{1f248}'), ('\u{1f250}', - '\u{1f251}'), ('\u{1f300}', '\u{1f32c}'), ('\u{1f330}', '\u{1f37d}'), ('\u{1f380}', - '\u{1f3ce}'), ('\u{1f3d4}', '\u{1f3f7}'), ('\u{1f400}', '\u{1f4fe}'), ('\u{1f500}', - '\u{1f54a}'), ('\u{1f550}', '\u{1f579}'), ('\u{1f57b}', '\u{1f5a3}'), ('\u{1f5a5}', - '\u{1f642}'), ('\u{1f645}', '\u{1f6cf}'), ('\u{1f6e0}', '\u{1f6ec}'), ('\u{1f6f0}', - '\u{1f6f3}'), ('\u{1f700}', '\u{1f773}'), ('\u{1f780}', '\u{1f7d4}'), ('\u{1f800}', - '\u{1f80b}'), ('\u{1f810}', '\u{1f847}'), ('\u{1f850}', '\u{1f859}'), ('\u{1f860}', - '\u{1f887}'), ('\u{1f890}', '\u{1f8ad}') - ]; - - pub const Z_table: &'static [(char, char)] = &[ - ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), ('\u{2000}', - '\u{200a}'), ('\u{2028}', '\u{2029}'), ('\u{202f}', '\u{202f}'), ('\u{205f}', '\u{205f}'), - ('\u{3000}', '\u{3000}') - ]; - - pub const Zl_table: &'static [(char, char)] = &[ - ('\u{2028}', '\u{2028}') - ]; - - pub const Zp_table: &'static [(char, char)] = &[ - ('\u{2029}', '\u{2029}') - ]; - - pub const Zs_table: &'static [(char, char)] = &[ - ('\u{20}', '\u{20}'), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), ('\u{2000}', - '\u{200a}'), ('\u{202f}', '\u{202f}'), ('\u{205f}', '\u{205f}'), ('\u{3000}', '\u{3000}') - ]; - -} +} pub mod derived_property { pub const Alphabetic_table: &'static [(char, char)] = &[ @@ -2048,17 +342,6 @@ pub mod derived_property { super::bsearch_range_table(c, Alphabetic_table) } - pub const Default_Ignorable_Code_Point_table: &'static [(char, char)] = &[ - ('\u{ad}', '\u{ad}'), ('\u{34f}', '\u{34f}'), ('\u{61c}', '\u{61c}'), ('\u{115f}', - '\u{1160}'), ('\u{17b4}', '\u{17b5}'), ('\u{180b}', '\u{180d}'), ('\u{180e}', '\u{180e}'), - ('\u{200b}', '\u{200f}'), ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'), ('\u{2065}', - '\u{2065}'), ('\u{2066}', '\u{206f}'), ('\u{3164}', '\u{3164}'), ('\u{fe00}', '\u{fe0f}'), - ('\u{feff}', '\u{feff}'), ('\u{ffa0}', '\u{ffa0}'), ('\u{fff0}', '\u{fff8}'), ('\u{1bca0}', - '\u{1bca3}'), ('\u{1d173}', '\u{1d17a}'), ('\u{e0000}', '\u{e0000}'), ('\u{e0001}', - '\u{e0001}'), ('\u{e0002}', '\u{e001f}'), ('\u{e0020}', '\u{e007f}'), ('\u{e0080}', - '\u{e00ff}'), ('\u{e0100}', '\u{e01ef}'), ('\u{e01f0}', '\u{e0fff}') - ]; - pub const Lowercase_table: &'static [(char, char)] = &[ ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{ba}', '\u{ba}'), ('\u{df}', '\u{f6}'), ('\u{f8}', '\u{ff}'), ('\u{101}', '\u{101}'), ('\u{103}', '\u{103}'), @@ -2740,1198 +1023,224 @@ pub mod derived_property { ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), - ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), - ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), - ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), - ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), - ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), - ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1d7ce}', '\u{1d7ff}'), - ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1ee00}', '\u{1ee03}'), - ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), - ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), - ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), - ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), - ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), - ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), - ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), - ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), - ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), - ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), - ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), - ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', '\u{2fa1d}'), - ('\u{e0100}', '\u{e01ef}') - ]; - - pub fn XID_Continue(c: char) -> bool { - super::bsearch_range_table(c, XID_Continue_table) - } - - pub const XID_Start_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), - ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'), - ('\u{1bb}', '\u{1bb}'), ('\u{1bc}', '\u{1bf}'), ('\u{1c0}', '\u{1c3}'), ('\u{1c4}', - '\u{293}'), ('\u{294}', '\u{294}'), ('\u{295}', '\u{2af}'), ('\u{2b0}', '\u{2c1}'), - ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', - '\u{2ee}'), ('\u{370}', '\u{373}'), ('\u{374}', '\u{374}'), ('\u{376}', '\u{377}'), - ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', - '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), - ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', - '\u{559}'), ('\u{561}', '\u{587}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), - ('\u{620}', '\u{63f}'), ('\u{640}', '\u{640}'), ('\u{641}', '\u{64a}'), ('\u{66e}', - '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}', '\u{6e6}'), - ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}', - '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}', '\u{7b1}'), - ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{800}', - '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}', '\u{828}'), - ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b2}'), ('\u{904}', '\u{939}'), ('\u{93d}', - '\u{93d}'), ('\u{950}', '\u{950}'), ('\u{958}', '\u{961}'), ('\u{971}', '\u{971}'), - ('\u{972}', '\u{980}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', - '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), - ('\u{9bd}', '\u{9bd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', - '\u{9e1}'), ('\u{9f0}', '\u{9f1}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), - ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', - '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), - ('\u{a72}', '\u{a74}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', - '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), - ('\u{abd}', '\u{abd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{b05}', - '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), - ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b3d}'), ('\u{b5c}', - '\u{b5d}'), ('\u{b5f}', '\u{b61}'), ('\u{b71}', '\u{b71}'), ('\u{b83}', '\u{b83}'), - ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', - '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), - ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), ('\u{c05}', - '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), - ('\u{c3d}', '\u{c3d}'), ('\u{c58}', '\u{c59}'), ('\u{c60}', '\u{c61}'), ('\u{c85}', - '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), - ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cbd}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', - '\u{ce1}'), ('\u{cf1}', '\u{cf2}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), - ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d60}', - '\u{d61}'), ('\u{d7a}', '\u{d7f}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), - ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', - '\u{e30}'), ('\u{e32}', '\u{e32}'), ('\u{e40}', '\u{e45}'), ('\u{e46}', '\u{e46}'), - ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', - '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), - ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', - '\u{eab}'), ('\u{ead}', '\u{eb0}'), ('\u{eb2}', '\u{eb2}'), ('\u{ebd}', '\u{ebd}'), - ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', - '\u{f00}'), ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), - ('\u{1000}', '\u{102a}'), ('\u{103f}', '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', - '\u{105d}'), ('\u{1061}', '\u{1061}'), ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), - ('\u{1075}', '\u{1081}'), ('\u{108e}', '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', - '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{10fc}'), - ('\u{10fd}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', - '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), - ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', - '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), - ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', - '\u{13f4}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), - ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f0}'), ('\u{16f1}', '\u{16f8}'), ('\u{1700}', - '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1720}', '\u{1731}'), ('\u{1740}', '\u{1751}'), - ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1780}', '\u{17b3}'), ('\u{17d7}', - '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1842}'), ('\u{1843}', '\u{1843}'), - ('\u{1844}', '\u{1877}'), ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', - '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), - ('\u{1980}', '\u{19ab}'), ('\u{19c1}', '\u{19c7}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', - '\u{1a54}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), - ('\u{1b83}', '\u{1ba0}'), ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', - '\u{1c23}'), ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', '\u{1c77}'), ('\u{1c78}', '\u{1c7d}'), - ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), ('\u{1cf5}', '\u{1cf6}'), ('\u{1d00}', - '\u{1d2b}'), ('\u{1d2c}', '\u{1d6a}'), ('\u{1d6b}', '\u{1d77}'), ('\u{1d78}', '\u{1d78}'), - ('\u{1d79}', '\u{1d9a}'), ('\u{1d9b}', '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', - '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), - ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', - '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), - ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', - '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), - ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}', - '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), - ('\u{2118}', '\u{2118}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', - '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), ('\u{212e}', '\u{212e}'), - ('\u{212f}', '\u{2134}'), ('\u{2135}', '\u{2138}'), ('\u{2139}', '\u{2139}'), ('\u{213c}', - '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2182}'), - ('\u{2183}', '\u{2184}'), ('\u{2185}', '\u{2188}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', - '\u{2c5e}'), ('\u{2c60}', '\u{2c7b}'), ('\u{2c7c}', '\u{2c7d}'), ('\u{2c7e}', '\u{2ce4}'), - ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', - '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), - ('\u{2d80}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', - '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), - ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{3005}', '\u{3005}'), ('\u{3006}', - '\u{3006}'), ('\u{3007}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3031}', '\u{3035}'), - ('\u{3038}', '\u{303a}'), ('\u{303b}', '\u{303b}'), ('\u{303c}', '\u{303c}'), ('\u{3041}', - '\u{3096}'), ('\u{309d}', '\u{309e}'), ('\u{309f}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), - ('\u{30fc}', '\u{30fe}'), ('\u{30ff}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', - '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), - ('\u{4e00}', '\u{9fcc}'), ('\u{a000}', '\u{a014}'), ('\u{a015}', '\u{a015}'), ('\u{a016}', - '\u{a48c}'), ('\u{a4d0}', '\u{a4f7}'), ('\u{a4f8}', '\u{a4fd}'), ('\u{a500}', '\u{a60b}'), - ('\u{a60c}', '\u{a60c}'), ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', - '\u{a66d}'), ('\u{a66e}', '\u{a66e}'), ('\u{a67f}', '\u{a67f}'), ('\u{a680}', '\u{a69b}'), - ('\u{a69c}', '\u{a69d}'), ('\u{a6a0}', '\u{a6e5}'), ('\u{a6e6}', '\u{a6ef}'), ('\u{a717}', - '\u{a71f}'), ('\u{a722}', '\u{a76f}'), ('\u{a770}', '\u{a770}'), ('\u{a771}', '\u{a787}'), - ('\u{a788}', '\u{a788}'), ('\u{a78b}', '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', - '\u{a7b1}'), ('\u{a7f7}', '\u{a7f7}'), ('\u{a7f8}', '\u{a7f9}'), ('\u{a7fa}', '\u{a7fa}'), - ('\u{a7fb}', '\u{a801}'), ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', - '\u{a822}'), ('\u{a840}', '\u{a873}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), - ('\u{a8fb}', '\u{a8fb}'), ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), ('\u{a960}', - '\u{a97c}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), - ('\u{a9e6}', '\u{a9e6}'), ('\u{a9e7}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', - '\u{aa28}'), ('\u{aa40}', '\u{aa42}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa6f}'), - ('\u{aa70}', '\u{aa70}'), ('\u{aa71}', '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), ('\u{aa7e}', - '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', '\u{aabd}'), - ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadc}'), ('\u{aadd}', - '\u{aadd}'), ('\u{aae0}', '\u{aaea}'), ('\u{aaf2}', '\u{aaf2}'), ('\u{aaf3}', '\u{aaf4}'), - ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', - '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab5f}'), - ('\u{ab64}', '\u{ab65}'), ('\u{abc0}', '\u{abe2}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', - '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), - ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb1d}'), ('\u{fb1f}', - '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), - ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', - '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), - ('\u{fdf0}', '\u{fdf9}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', '\u{fe73}'), ('\u{fe77}', - '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), ('\u{fe7d}', '\u{fe7d}'), - ('\u{fe7f}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', - '\u{ff6f}'), ('\u{ff70}', '\u{ff70}'), ('\u{ff71}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), - ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', - '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', - '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', - '\u{1005d}'), ('\u{10080}', '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{10280}', - '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', - '\u{10340}'), ('\u{10341}', '\u{10341}'), ('\u{10342}', '\u{10349}'), ('\u{1034a}', - '\u{1034a}'), ('\u{10350}', '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', - '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', - '\u{1044f}'), ('\u{10450}', '\u{1049d}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', - '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', - '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', - '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', - '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{10900}', - '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', - '\u{109bf}'), ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', - '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', - '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', - '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', - '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{11003}', '\u{11037}'), ('\u{11083}', - '\u{110af}'), ('\u{110d0}', '\u{110e8}'), ('\u{11103}', '\u{11126}'), ('\u{11150}', - '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11183}', '\u{111b2}'), ('\u{111c1}', - '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', - '\u{1122b}'), ('\u{112b0}', '\u{112de}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', - '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', - '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}', '\u{1133d}'), ('\u{1135d}', - '\u{11361}'), ('\u{11480}', '\u{114af}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', - '\u{114c7}'), ('\u{11580}', '\u{115ae}'), ('\u{11600}', '\u{1162f}'), ('\u{11644}', - '\u{11644}'), ('\u{11680}', '\u{116aa}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', - '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{12000}', '\u{12398}'), ('\u{12400}', - '\u{1246e}'), ('\u{13000}', '\u{1342e}'), ('\u{16800}', '\u{16a38}'), ('\u{16a40}', - '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'), ('\u{16b40}', - '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), ('\u{16f00}', - '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{16f93}', '\u{16f9f}'), ('\u{1b000}', - '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', - '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', - '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', - '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', - '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', - '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', - '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', - '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', - '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', - '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', - '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', - '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1ee00}', - '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', - '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', - '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', - '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', - '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', - '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', - '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', - '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', - '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', - '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', - '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', - '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', - '\u{2fa1d}') - ]; - - pub fn XID_Start(c: char) -> bool { - super::bsearch_range_table(c, XID_Start_table) - } - -} - -pub mod script { - pub const Arabic_table: &'static [(char, char)] = &[ - ('\u{600}', '\u{604}'), ('\u{606}', '\u{608}'), ('\u{609}', '\u{60a}'), ('\u{60b}', - '\u{60b}'), ('\u{60d}', '\u{60d}'), ('\u{60e}', '\u{60f}'), ('\u{610}', '\u{61a}'), - ('\u{61e}', '\u{61e}'), ('\u{620}', '\u{63f}'), ('\u{641}', '\u{64a}'), ('\u{656}', - '\u{65f}'), ('\u{66a}', '\u{66d}'), ('\u{66e}', '\u{66f}'), ('\u{671}', '\u{6d3}'), - ('\u{6d4}', '\u{6d4}'), ('\u{6d5}', '\u{6d5}'), ('\u{6d6}', '\u{6dc}'), ('\u{6de}', - '\u{6de}'), ('\u{6df}', '\u{6e4}'), ('\u{6e5}', '\u{6e6}'), ('\u{6e7}', '\u{6e8}'), - ('\u{6e9}', '\u{6e9}'), ('\u{6ea}', '\u{6ed}'), ('\u{6ee}', '\u{6ef}'), ('\u{6f0}', - '\u{6f9}'), ('\u{6fa}', '\u{6fc}'), ('\u{6fd}', '\u{6fe}'), ('\u{6ff}', '\u{6ff}'), - ('\u{750}', '\u{77f}'), ('\u{8a0}', '\u{8b2}'), ('\u{8e4}', '\u{8ff}'), ('\u{fb50}', - '\u{fbb1}'), ('\u{fbb2}', '\u{fbc1}'), ('\u{fbd3}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), - ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdfb}'), ('\u{fdfc}', '\u{fdfc}'), ('\u{fdfd}', - '\u{fdfd}'), ('\u{fe70}', '\u{fe74}'), ('\u{fe76}', '\u{fefc}'), ('\u{10e60}', '\u{10e7e}'), - ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), - ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), - ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), - ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), - ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), - ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), - ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), - ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), - ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), - ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), - ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), - ('\u{1eef0}', '\u{1eef1}') - ]; - - pub const Armenian_table: &'static [(char, char)] = &[ - ('\u{531}', '\u{556}'), ('\u{559}', '\u{559}'), ('\u{55a}', '\u{55f}'), ('\u{561}', - '\u{587}'), ('\u{58a}', '\u{58a}'), ('\u{58d}', '\u{58e}'), ('\u{58f}', '\u{58f}'), - ('\u{fb13}', '\u{fb17}') - ]; - - pub const Avestan_table: &'static [(char, char)] = &[ - ('\u{10b00}', '\u{10b35}'), ('\u{10b39}', '\u{10b3f}') - ]; - - pub const Balinese_table: &'static [(char, char)] = &[ - ('\u{1b00}', '\u{1b03}'), ('\u{1b04}', '\u{1b04}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b34}', - '\u{1b34}'), ('\u{1b35}', '\u{1b35}'), ('\u{1b36}', '\u{1b3a}'), ('\u{1b3b}', '\u{1b3b}'), - ('\u{1b3c}', '\u{1b3c}'), ('\u{1b3d}', '\u{1b41}'), ('\u{1b42}', '\u{1b42}'), ('\u{1b43}', - '\u{1b44}'), ('\u{1b45}', '\u{1b4b}'), ('\u{1b50}', '\u{1b59}'), ('\u{1b5a}', '\u{1b60}'), - ('\u{1b61}', '\u{1b6a}'), ('\u{1b6b}', '\u{1b73}'), ('\u{1b74}', '\u{1b7c}') - ]; - - pub const Bamum_table: &'static [(char, char)] = &[ - ('\u{a6a0}', '\u{a6e5}'), ('\u{a6e6}', '\u{a6ef}'), ('\u{a6f0}', '\u{a6f1}'), ('\u{a6f2}', - '\u{a6f7}'), ('\u{16800}', '\u{16a38}') - ]; - - pub const Bassa_Vah_table: &'static [(char, char)] = &[ - ('\u{16ad0}', '\u{16aed}'), ('\u{16af0}', '\u{16af4}'), ('\u{16af5}', '\u{16af5}') - ]; - - pub const Batak_table: &'static [(char, char)] = &[ - ('\u{1bc0}', '\u{1be5}'), ('\u{1be6}', '\u{1be6}'), ('\u{1be7}', '\u{1be7}'), ('\u{1be8}', - '\u{1be9}'), ('\u{1bea}', '\u{1bec}'), ('\u{1bed}', '\u{1bed}'), ('\u{1bee}', '\u{1bee}'), - ('\u{1bef}', '\u{1bf1}'), ('\u{1bf2}', '\u{1bf3}'), ('\u{1bfc}', '\u{1bff}') - ]; - - pub const Bengali_table: &'static [(char, char)] = &[ - ('\u{980}', '\u{980}'), ('\u{981}', '\u{981}'), ('\u{982}', '\u{983}'), ('\u{985}', - '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), - ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), ('\u{9bc}', '\u{9bc}'), ('\u{9bd}', - '\u{9bd}'), ('\u{9be}', '\u{9c0}'), ('\u{9c1}', '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), - ('\u{9cb}', '\u{9cc}'), ('\u{9cd}', '\u{9cd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9d7}', - '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e1}'), ('\u{9e2}', '\u{9e3}'), - ('\u{9e6}', '\u{9ef}'), ('\u{9f0}', '\u{9f1}'), ('\u{9f2}', '\u{9f3}'), ('\u{9f4}', - '\u{9f9}'), ('\u{9fa}', '\u{9fa}'), ('\u{9fb}', '\u{9fb}') - ]; - - pub const Bopomofo_table: &'static [(char, char)] = &[ - ('\u{2ea}', '\u{2eb}'), ('\u{3105}', '\u{312d}'), ('\u{31a0}', '\u{31ba}') - ]; - - pub const Brahmi_table: &'static [(char, char)] = &[ - ('\u{11000}', '\u{11000}'), ('\u{11001}', '\u{11001}'), ('\u{11002}', '\u{11002}'), - ('\u{11003}', '\u{11037}'), ('\u{11038}', '\u{11046}'), ('\u{11047}', '\u{1104d}'), - ('\u{11052}', '\u{11065}'), ('\u{11066}', '\u{1106f}'), ('\u{1107f}', '\u{1107f}') - ]; - - pub const Braille_table: &'static [(char, char)] = &[ - ('\u{2800}', '\u{28ff}') - ]; - - pub const Buginese_table: &'static [(char, char)] = &[ - ('\u{1a00}', '\u{1a16}'), ('\u{1a17}', '\u{1a18}'), ('\u{1a19}', '\u{1a1a}'), ('\u{1a1b}', - '\u{1a1b}'), ('\u{1a1e}', '\u{1a1f}') - ]; - - pub const Buhid_table: &'static [(char, char)] = &[ - ('\u{1740}', '\u{1751}'), ('\u{1752}', '\u{1753}') - ]; - - pub const Canadian_Aboriginal_table: &'static [(char, char)] = &[ - ('\u{1400}', '\u{1400}'), ('\u{1401}', '\u{166c}'), ('\u{166d}', '\u{166e}'), ('\u{166f}', - '\u{167f}'), ('\u{18b0}', '\u{18f5}') - ]; - - pub const Carian_table: &'static [(char, char)] = &[ - ('\u{102a0}', '\u{102d0}') - ]; - - pub const Caucasian_Albanian_table: &'static [(char, char)] = &[ - ('\u{10530}', '\u{10563}'), ('\u{1056f}', '\u{1056f}') - ]; - - pub const Chakma_table: &'static [(char, char)] = &[ - ('\u{11100}', '\u{11102}'), ('\u{11103}', '\u{11126}'), ('\u{11127}', '\u{1112b}'), - ('\u{1112c}', '\u{1112c}'), ('\u{1112d}', '\u{11134}'), ('\u{11136}', '\u{1113f}'), - ('\u{11140}', '\u{11143}') - ]; - - pub const Cham_table: &'static [(char, char)] = &[ - ('\u{aa00}', '\u{aa28}'), ('\u{aa29}', '\u{aa2e}'), ('\u{aa2f}', '\u{aa30}'), ('\u{aa31}', - '\u{aa32}'), ('\u{aa33}', '\u{aa34}'), ('\u{aa35}', '\u{aa36}'), ('\u{aa40}', '\u{aa42}'), - ('\u{aa43}', '\u{aa43}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa4c}', '\u{aa4c}'), ('\u{aa4d}', - '\u{aa4d}'), ('\u{aa50}', '\u{aa59}'), ('\u{aa5c}', '\u{aa5f}') - ]; - - pub const Cherokee_table: &'static [(char, char)] = &[ - ('\u{13a0}', '\u{13f4}') - ]; - - pub const Common_table: &'static [(char, char)] = &[ - ('\u{0}', '\u{1f}'), ('\u{20}', '\u{20}'), ('\u{21}', '\u{23}'), ('\u{24}', '\u{24}'), - ('\u{25}', '\u{27}'), ('\u{28}', '\u{28}'), ('\u{29}', '\u{29}'), ('\u{2a}', '\u{2a}'), - ('\u{2b}', '\u{2b}'), ('\u{2c}', '\u{2c}'), ('\u{2d}', '\u{2d}'), ('\u{2e}', '\u{2f}'), - ('\u{30}', '\u{39}'), ('\u{3a}', '\u{3b}'), ('\u{3c}', '\u{3e}'), ('\u{3f}', '\u{40}'), - ('\u{5b}', '\u{5b}'), ('\u{5c}', '\u{5c}'), ('\u{5d}', '\u{5d}'), ('\u{5e}', '\u{5e}'), - ('\u{5f}', '\u{5f}'), ('\u{60}', '\u{60}'), ('\u{7b}', '\u{7b}'), ('\u{7c}', '\u{7c}'), - ('\u{7d}', '\u{7d}'), ('\u{7e}', '\u{7e}'), ('\u{7f}', '\u{9f}'), ('\u{a0}', '\u{a0}'), - ('\u{a1}', '\u{a1}'), ('\u{a2}', '\u{a5}'), ('\u{a6}', '\u{a6}'), ('\u{a7}', '\u{a7}'), - ('\u{a8}', '\u{a8}'), ('\u{a9}', '\u{a9}'), ('\u{ab}', '\u{ab}'), ('\u{ac}', '\u{ac}'), - ('\u{ad}', '\u{ad}'), ('\u{ae}', '\u{ae}'), ('\u{af}', '\u{af}'), ('\u{b0}', '\u{b0}'), - ('\u{b1}', '\u{b1}'), ('\u{b2}', '\u{b3}'), ('\u{b4}', '\u{b4}'), ('\u{b5}', '\u{b5}'), - ('\u{b6}', '\u{b7}'), ('\u{b8}', '\u{b8}'), ('\u{b9}', '\u{b9}'), ('\u{bb}', '\u{bb}'), - ('\u{bc}', '\u{be}'), ('\u{bf}', '\u{bf}'), ('\u{d7}', '\u{d7}'), ('\u{f7}', '\u{f7}'), - ('\u{2b9}', '\u{2c1}'), ('\u{2c2}', '\u{2c5}'), ('\u{2c6}', '\u{2d1}'), ('\u{2d2}', - '\u{2df}'), ('\u{2e5}', '\u{2e9}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ed}', '\u{2ed}'), - ('\u{2ee}', '\u{2ee}'), ('\u{2ef}', '\u{2ff}'), ('\u{374}', '\u{374}'), ('\u{37e}', - '\u{37e}'), ('\u{385}', '\u{385}'), ('\u{387}', '\u{387}'), ('\u{589}', '\u{589}'), - ('\u{605}', '\u{605}'), ('\u{60c}', '\u{60c}'), ('\u{61b}', '\u{61b}'), ('\u{61c}', - '\u{61c}'), ('\u{61f}', '\u{61f}'), ('\u{640}', '\u{640}'), ('\u{660}', '\u{669}'), - ('\u{6dd}', '\u{6dd}'), ('\u{964}', '\u{965}'), ('\u{e3f}', '\u{e3f}'), ('\u{fd5}', - '\u{fd8}'), ('\u{10fb}', '\u{10fb}'), ('\u{16eb}', '\u{16ed}'), ('\u{1735}', '\u{1736}'), - ('\u{1802}', '\u{1803}'), ('\u{1805}', '\u{1805}'), ('\u{1cd3}', '\u{1cd3}'), ('\u{1ce1}', - '\u{1ce1}'), ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), ('\u{1cf2}', '\u{1cf3}'), - ('\u{1cf5}', '\u{1cf6}'), ('\u{2000}', '\u{200a}'), ('\u{200b}', '\u{200b}'), ('\u{200e}', - '\u{200f}'), ('\u{2010}', '\u{2015}'), ('\u{2016}', '\u{2017}'), ('\u{2018}', '\u{2018}'), - ('\u{2019}', '\u{2019}'), ('\u{201a}', '\u{201a}'), ('\u{201b}', '\u{201c}'), ('\u{201d}', - '\u{201d}'), ('\u{201e}', '\u{201e}'), ('\u{201f}', '\u{201f}'), ('\u{2020}', '\u{2027}'), - ('\u{2028}', '\u{2028}'), ('\u{2029}', '\u{2029}'), ('\u{202a}', '\u{202e}'), ('\u{202f}', - '\u{202f}'), ('\u{2030}', '\u{2038}'), ('\u{2039}', '\u{2039}'), ('\u{203a}', '\u{203a}'), - ('\u{203b}', '\u{203e}'), ('\u{203f}', '\u{2040}'), ('\u{2041}', '\u{2043}'), ('\u{2044}', - '\u{2044}'), ('\u{2045}', '\u{2045}'), ('\u{2046}', '\u{2046}'), ('\u{2047}', '\u{2051}'), - ('\u{2052}', '\u{2052}'), ('\u{2053}', '\u{2053}'), ('\u{2054}', '\u{2054}'), ('\u{2055}', - '\u{205e}'), ('\u{205f}', '\u{205f}'), ('\u{2060}', '\u{2064}'), ('\u{2066}', '\u{206f}'), - ('\u{2070}', '\u{2070}'), ('\u{2074}', '\u{2079}'), ('\u{207a}', '\u{207c}'), ('\u{207d}', - '\u{207d}'), ('\u{207e}', '\u{207e}'), ('\u{2080}', '\u{2089}'), ('\u{208a}', '\u{208c}'), - ('\u{208d}', '\u{208d}'), ('\u{208e}', '\u{208e}'), ('\u{20a0}', '\u{20bd}'), ('\u{2100}', - '\u{2101}'), ('\u{2102}', '\u{2102}'), ('\u{2103}', '\u{2106}'), ('\u{2107}', '\u{2107}'), - ('\u{2108}', '\u{2109}'), ('\u{210a}', '\u{2113}'), ('\u{2114}', '\u{2114}'), ('\u{2115}', - '\u{2115}'), ('\u{2116}', '\u{2117}'), ('\u{2118}', '\u{2118}'), ('\u{2119}', '\u{211d}'), - ('\u{211e}', '\u{2123}'), ('\u{2124}', '\u{2124}'), ('\u{2125}', '\u{2125}'), ('\u{2127}', - '\u{2127}'), ('\u{2128}', '\u{2128}'), ('\u{2129}', '\u{2129}'), ('\u{212c}', '\u{212d}'), - ('\u{212e}', '\u{212e}'), ('\u{212f}', '\u{2131}'), ('\u{2133}', '\u{2134}'), ('\u{2135}', - '\u{2138}'), ('\u{2139}', '\u{2139}'), ('\u{213a}', '\u{213b}'), ('\u{213c}', '\u{213f}'), - ('\u{2140}', '\u{2144}'), ('\u{2145}', '\u{2149}'), ('\u{214a}', '\u{214a}'), ('\u{214b}', - '\u{214b}'), ('\u{214c}', '\u{214d}'), ('\u{214f}', '\u{214f}'), ('\u{2150}', '\u{215f}'), - ('\u{2189}', '\u{2189}'), ('\u{2190}', '\u{2194}'), ('\u{2195}', '\u{2199}'), ('\u{219a}', - '\u{219b}'), ('\u{219c}', '\u{219f}'), ('\u{21a0}', '\u{21a0}'), ('\u{21a1}', '\u{21a2}'), - ('\u{21a3}', '\u{21a3}'), ('\u{21a4}', '\u{21a5}'), ('\u{21a6}', '\u{21a6}'), ('\u{21a7}', - '\u{21ad}'), ('\u{21ae}', '\u{21ae}'), ('\u{21af}', '\u{21cd}'), ('\u{21ce}', '\u{21cf}'), - ('\u{21d0}', '\u{21d1}'), ('\u{21d2}', '\u{21d2}'), ('\u{21d3}', '\u{21d3}'), ('\u{21d4}', - '\u{21d4}'), ('\u{21d5}', '\u{21f3}'), ('\u{21f4}', '\u{22ff}'), ('\u{2300}', '\u{2307}'), - ('\u{2308}', '\u{2308}'), ('\u{2309}', '\u{2309}'), ('\u{230a}', '\u{230a}'), ('\u{230b}', - '\u{230b}'), ('\u{230c}', '\u{231f}'), ('\u{2320}', '\u{2321}'), ('\u{2322}', '\u{2328}'), - ('\u{2329}', '\u{2329}'), ('\u{232a}', '\u{232a}'), ('\u{232b}', '\u{237b}'), ('\u{237c}', - '\u{237c}'), ('\u{237d}', '\u{239a}'), ('\u{239b}', '\u{23b3}'), ('\u{23b4}', '\u{23db}'), - ('\u{23dc}', '\u{23e1}'), ('\u{23e2}', '\u{23fa}'), ('\u{2400}', '\u{2426}'), ('\u{2440}', - '\u{244a}'), ('\u{2460}', '\u{249b}'), ('\u{249c}', '\u{24e9}'), ('\u{24ea}', '\u{24ff}'), - ('\u{2500}', '\u{25b6}'), ('\u{25b7}', '\u{25b7}'), ('\u{25b8}', '\u{25c0}'), ('\u{25c1}', - '\u{25c1}'), ('\u{25c2}', '\u{25f7}'), ('\u{25f8}', '\u{25ff}'), ('\u{2600}', '\u{266e}'), - ('\u{266f}', '\u{266f}'), ('\u{2670}', '\u{2767}'), ('\u{2768}', '\u{2768}'), ('\u{2769}', - '\u{2769}'), ('\u{276a}', '\u{276a}'), ('\u{276b}', '\u{276b}'), ('\u{276c}', '\u{276c}'), - ('\u{276d}', '\u{276d}'), ('\u{276e}', '\u{276e}'), ('\u{276f}', '\u{276f}'), ('\u{2770}', - '\u{2770}'), ('\u{2771}', '\u{2771}'), ('\u{2772}', '\u{2772}'), ('\u{2773}', '\u{2773}'), - ('\u{2774}', '\u{2774}'), ('\u{2775}', '\u{2775}'), ('\u{2776}', '\u{2793}'), ('\u{2794}', - '\u{27bf}'), ('\u{27c0}', '\u{27c4}'), ('\u{27c5}', '\u{27c5}'), ('\u{27c6}', '\u{27c6}'), - ('\u{27c7}', '\u{27e5}'), ('\u{27e6}', '\u{27e6}'), ('\u{27e7}', '\u{27e7}'), ('\u{27e8}', - '\u{27e8}'), ('\u{27e9}', '\u{27e9}'), ('\u{27ea}', '\u{27ea}'), ('\u{27eb}', '\u{27eb}'), - ('\u{27ec}', '\u{27ec}'), ('\u{27ed}', '\u{27ed}'), ('\u{27ee}', '\u{27ee}'), ('\u{27ef}', - '\u{27ef}'), ('\u{27f0}', '\u{27ff}'), ('\u{2900}', '\u{2982}'), ('\u{2983}', '\u{2983}'), - ('\u{2984}', '\u{2984}'), ('\u{2985}', '\u{2985}'), ('\u{2986}', '\u{2986}'), ('\u{2987}', - '\u{2987}'), ('\u{2988}', '\u{2988}'), ('\u{2989}', '\u{2989}'), ('\u{298a}', '\u{298a}'), - ('\u{298b}', '\u{298b}'), ('\u{298c}', '\u{298c}'), ('\u{298d}', '\u{298d}'), ('\u{298e}', - '\u{298e}'), ('\u{298f}', '\u{298f}'), ('\u{2990}', '\u{2990}'), ('\u{2991}', '\u{2991}'), - ('\u{2992}', '\u{2992}'), ('\u{2993}', '\u{2993}'), ('\u{2994}', '\u{2994}'), ('\u{2995}', - '\u{2995}'), ('\u{2996}', '\u{2996}'), ('\u{2997}', '\u{2997}'), ('\u{2998}', '\u{2998}'), - ('\u{2999}', '\u{29d7}'), ('\u{29d8}', '\u{29d8}'), ('\u{29d9}', '\u{29d9}'), ('\u{29da}', - '\u{29da}'), ('\u{29db}', '\u{29db}'), ('\u{29dc}', '\u{29fb}'), ('\u{29fc}', '\u{29fc}'), - ('\u{29fd}', '\u{29fd}'), ('\u{29fe}', '\u{2aff}'), ('\u{2b00}', '\u{2b2f}'), ('\u{2b30}', - '\u{2b44}'), ('\u{2b45}', '\u{2b46}'), ('\u{2b47}', '\u{2b4c}'), ('\u{2b4d}', '\u{2b73}'), - ('\u{2b76}', '\u{2b95}'), ('\u{2b98}', '\u{2bb9}'), ('\u{2bbd}', '\u{2bc8}'), ('\u{2bca}', - '\u{2bd1}'), ('\u{2e00}', '\u{2e01}'), ('\u{2e02}', '\u{2e02}'), ('\u{2e03}', '\u{2e03}'), - ('\u{2e04}', '\u{2e04}'), ('\u{2e05}', '\u{2e05}'), ('\u{2e06}', '\u{2e08}'), ('\u{2e09}', - '\u{2e09}'), ('\u{2e0a}', '\u{2e0a}'), ('\u{2e0b}', '\u{2e0b}'), ('\u{2e0c}', '\u{2e0c}'), - ('\u{2e0d}', '\u{2e0d}'), ('\u{2e0e}', '\u{2e16}'), ('\u{2e17}', '\u{2e17}'), ('\u{2e18}', - '\u{2e19}'), ('\u{2e1a}', '\u{2e1a}'), ('\u{2e1b}', '\u{2e1b}'), ('\u{2e1c}', '\u{2e1c}'), - ('\u{2e1d}', '\u{2e1d}'), ('\u{2e1e}', '\u{2e1f}'), ('\u{2e20}', '\u{2e20}'), ('\u{2e21}', - '\u{2e21}'), ('\u{2e22}', '\u{2e22}'), ('\u{2e23}', '\u{2e23}'), ('\u{2e24}', '\u{2e24}'), - ('\u{2e25}', '\u{2e25}'), ('\u{2e26}', '\u{2e26}'), ('\u{2e27}', '\u{2e27}'), ('\u{2e28}', - '\u{2e28}'), ('\u{2e29}', '\u{2e29}'), ('\u{2e2a}', '\u{2e2e}'), ('\u{2e2f}', '\u{2e2f}'), - ('\u{2e30}', '\u{2e39}'), ('\u{2e3a}', '\u{2e3b}'), ('\u{2e3c}', '\u{2e3f}'), ('\u{2e40}', - '\u{2e40}'), ('\u{2e41}', '\u{2e41}'), ('\u{2e42}', '\u{2e42}'), ('\u{2ff0}', '\u{2ffb}'), - ('\u{3000}', '\u{3000}'), ('\u{3001}', '\u{3003}'), ('\u{3004}', '\u{3004}'), ('\u{3006}', - '\u{3006}'), ('\u{3008}', '\u{3008}'), ('\u{3009}', '\u{3009}'), ('\u{300a}', '\u{300a}'), - ('\u{300b}', '\u{300b}'), ('\u{300c}', '\u{300c}'), ('\u{300d}', '\u{300d}'), ('\u{300e}', - '\u{300e}'), ('\u{300f}', '\u{300f}'), ('\u{3010}', '\u{3010}'), ('\u{3011}', '\u{3011}'), - ('\u{3012}', '\u{3013}'), ('\u{3014}', '\u{3014}'), ('\u{3015}', '\u{3015}'), ('\u{3016}', - '\u{3016}'), ('\u{3017}', '\u{3017}'), ('\u{3018}', '\u{3018}'), ('\u{3019}', '\u{3019}'), - ('\u{301a}', '\u{301a}'), ('\u{301b}', '\u{301b}'), ('\u{301c}', '\u{301c}'), ('\u{301d}', - '\u{301d}'), ('\u{301e}', '\u{301f}'), ('\u{3020}', '\u{3020}'), ('\u{3030}', '\u{3030}'), - ('\u{3031}', '\u{3035}'), ('\u{3036}', '\u{3037}'), ('\u{303c}', '\u{303c}'), ('\u{303d}', - '\u{303d}'), ('\u{303e}', '\u{303f}'), ('\u{309b}', '\u{309c}'), ('\u{30a0}', '\u{30a0}'), - ('\u{30fb}', '\u{30fb}'), ('\u{30fc}', '\u{30fc}'), ('\u{3190}', '\u{3191}'), ('\u{3192}', - '\u{3195}'), ('\u{3196}', '\u{319f}'), ('\u{31c0}', '\u{31e3}'), ('\u{3220}', '\u{3229}'), - ('\u{322a}', '\u{3247}'), ('\u{3248}', '\u{324f}'), ('\u{3250}', '\u{3250}'), ('\u{3251}', - '\u{325f}'), ('\u{327f}', '\u{327f}'), ('\u{3280}', '\u{3289}'), ('\u{328a}', '\u{32b0}'), - ('\u{32b1}', '\u{32bf}'), ('\u{32c0}', '\u{32cf}'), ('\u{3358}', '\u{33ff}'), ('\u{4dc0}', - '\u{4dff}'), ('\u{a700}', '\u{a716}'), ('\u{a717}', '\u{a71f}'), ('\u{a720}', '\u{a721}'), - ('\u{a788}', '\u{a788}'), ('\u{a789}', '\u{a78a}'), ('\u{a830}', '\u{a835}'), ('\u{a836}', - '\u{a837}'), ('\u{a838}', '\u{a838}'), ('\u{a839}', '\u{a839}'), ('\u{a92e}', '\u{a92e}'), - ('\u{a9cf}', '\u{a9cf}'), ('\u{ab5b}', '\u{ab5b}'), ('\u{fd3e}', '\u{fd3e}'), ('\u{fd3f}', - '\u{fd3f}'), ('\u{fe10}', '\u{fe16}'), ('\u{fe17}', '\u{fe17}'), ('\u{fe18}', '\u{fe18}'), - ('\u{fe19}', '\u{fe19}'), ('\u{fe30}', '\u{fe30}'), ('\u{fe31}', '\u{fe32}'), ('\u{fe33}', - '\u{fe34}'), ('\u{fe35}', '\u{fe35}'), ('\u{fe36}', '\u{fe36}'), ('\u{fe37}', '\u{fe37}'), - ('\u{fe38}', '\u{fe38}'), ('\u{fe39}', '\u{fe39}'), ('\u{fe3a}', '\u{fe3a}'), ('\u{fe3b}', - '\u{fe3b}'), ('\u{fe3c}', '\u{fe3c}'), ('\u{fe3d}', '\u{fe3d}'), ('\u{fe3e}', '\u{fe3e}'), - ('\u{fe3f}', '\u{fe3f}'), ('\u{fe40}', '\u{fe40}'), ('\u{fe41}', '\u{fe41}'), ('\u{fe42}', - '\u{fe42}'), ('\u{fe43}', '\u{fe43}'), ('\u{fe44}', '\u{fe44}'), ('\u{fe45}', '\u{fe46}'), - ('\u{fe47}', '\u{fe47}'), ('\u{fe48}', '\u{fe48}'), ('\u{fe49}', '\u{fe4c}'), ('\u{fe4d}', - '\u{fe4f}'), ('\u{fe50}', '\u{fe52}'), ('\u{fe54}', '\u{fe57}'), ('\u{fe58}', '\u{fe58}'), - ('\u{fe59}', '\u{fe59}'), ('\u{fe5a}', '\u{fe5a}'), ('\u{fe5b}', '\u{fe5b}'), ('\u{fe5c}', - '\u{fe5c}'), ('\u{fe5d}', '\u{fe5d}'), ('\u{fe5e}', '\u{fe5e}'), ('\u{fe5f}', '\u{fe61}'), - ('\u{fe62}', '\u{fe62}'), ('\u{fe63}', '\u{fe63}'), ('\u{fe64}', '\u{fe66}'), ('\u{fe68}', - '\u{fe68}'), ('\u{fe69}', '\u{fe69}'), ('\u{fe6a}', '\u{fe6b}'), ('\u{feff}', '\u{feff}'), - ('\u{ff01}', '\u{ff03}'), ('\u{ff04}', '\u{ff04}'), ('\u{ff05}', '\u{ff07}'), ('\u{ff08}', - '\u{ff08}'), ('\u{ff09}', '\u{ff09}'), ('\u{ff0a}', '\u{ff0a}'), ('\u{ff0b}', '\u{ff0b}'), - ('\u{ff0c}', '\u{ff0c}'), ('\u{ff0d}', '\u{ff0d}'), ('\u{ff0e}', '\u{ff0f}'), ('\u{ff10}', - '\u{ff19}'), ('\u{ff1a}', '\u{ff1b}'), ('\u{ff1c}', '\u{ff1e}'), ('\u{ff1f}', '\u{ff20}'), - ('\u{ff3b}', '\u{ff3b}'), ('\u{ff3c}', '\u{ff3c}'), ('\u{ff3d}', '\u{ff3d}'), ('\u{ff3e}', - '\u{ff3e}'), ('\u{ff3f}', '\u{ff3f}'), ('\u{ff40}', '\u{ff40}'), ('\u{ff5b}', '\u{ff5b}'), - ('\u{ff5c}', '\u{ff5c}'), ('\u{ff5d}', '\u{ff5d}'), ('\u{ff5e}', '\u{ff5e}'), ('\u{ff5f}', - '\u{ff5f}'), ('\u{ff60}', '\u{ff60}'), ('\u{ff61}', '\u{ff61}'), ('\u{ff62}', '\u{ff62}'), - ('\u{ff63}', '\u{ff63}'), ('\u{ff64}', '\u{ff65}'), ('\u{ff70}', '\u{ff70}'), ('\u{ff9e}', - '\u{ff9f}'), ('\u{ffe0}', '\u{ffe1}'), ('\u{ffe2}', '\u{ffe2}'), ('\u{ffe3}', '\u{ffe3}'), - ('\u{ffe4}', '\u{ffe4}'), ('\u{ffe5}', '\u{ffe6}'), ('\u{ffe8}', '\u{ffe8}'), ('\u{ffe9}', - '\u{ffec}'), ('\u{ffed}', '\u{ffee}'), ('\u{fff9}', '\u{fffb}'), ('\u{fffc}', '\u{fffd}'), - ('\u{10100}', '\u{10102}'), ('\u{10107}', '\u{10133}'), ('\u{10137}', '\u{1013f}'), - ('\u{10190}', '\u{1019b}'), ('\u{101d0}', '\u{101fc}'), ('\u{102e1}', '\u{102fb}'), - ('\u{1bca0}', '\u{1bca3}'), ('\u{1d000}', '\u{1d0f5}'), ('\u{1d100}', '\u{1d126}'), - ('\u{1d129}', '\u{1d164}'), ('\u{1d165}', '\u{1d166}'), ('\u{1d16a}', '\u{1d16c}'), - ('\u{1d16d}', '\u{1d172}'), ('\u{1d173}', '\u{1d17a}'), ('\u{1d183}', '\u{1d184}'), - ('\u{1d18c}', '\u{1d1a9}'), ('\u{1d1ae}', '\u{1d1dd}'), ('\u{1d300}', '\u{1d356}'), - ('\u{1d360}', '\u{1d371}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), - ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), - ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), - ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), - ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), - ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), - ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), - ('\u{1d6c1}', '\u{1d6c1}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6db}', '\u{1d6db}'), - ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fb}', '\u{1d6fb}'), ('\u{1d6fc}', '\u{1d714}'), - ('\u{1d715}', '\u{1d715}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d735}', '\u{1d735}'), - ('\u{1d736}', '\u{1d74e}'), ('\u{1d74f}', '\u{1d74f}'), ('\u{1d750}', '\u{1d76e}'), - ('\u{1d76f}', '\u{1d76f}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d789}', '\u{1d789}'), - ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7a9}', '\u{1d7a9}'), ('\u{1d7aa}', '\u{1d7c2}'), - ('\u{1d7c3}', '\u{1d7c3}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1d7ce}', '\u{1d7ff}'), - ('\u{1f000}', '\u{1f02b}'), ('\u{1f030}', '\u{1f093}'), ('\u{1f0a0}', '\u{1f0ae}'), - ('\u{1f0b1}', '\u{1f0bf}'), ('\u{1f0c1}', '\u{1f0cf}'), ('\u{1f0d1}', '\u{1f0f5}'), - ('\u{1f100}', '\u{1f10c}'), ('\u{1f110}', '\u{1f12e}'), ('\u{1f130}', '\u{1f16b}'), - ('\u{1f170}', '\u{1f19a}'), ('\u{1f1e6}', '\u{1f1ff}'), ('\u{1f201}', '\u{1f202}'), - ('\u{1f210}', '\u{1f23a}'), ('\u{1f240}', '\u{1f248}'), ('\u{1f250}', '\u{1f251}'), - ('\u{1f300}', '\u{1f32c}'), ('\u{1f330}', '\u{1f37d}'), ('\u{1f380}', '\u{1f3ce}'), - ('\u{1f3d4}', '\u{1f3f7}'), ('\u{1f400}', '\u{1f4fe}'), ('\u{1f500}', '\u{1f54a}'), - ('\u{1f550}', '\u{1f579}'), ('\u{1f57b}', '\u{1f5a3}'), ('\u{1f5a5}', '\u{1f642}'), - ('\u{1f645}', '\u{1f6cf}'), ('\u{1f6e0}', '\u{1f6ec}'), ('\u{1f6f0}', '\u{1f6f3}'), - ('\u{1f700}', '\u{1f773}'), ('\u{1f780}', '\u{1f7d4}'), ('\u{1f800}', '\u{1f80b}'), - ('\u{1f810}', '\u{1f847}'), ('\u{1f850}', '\u{1f859}'), ('\u{1f860}', '\u{1f887}'), - ('\u{1f890}', '\u{1f8ad}'), ('\u{e0001}', '\u{e0001}'), ('\u{e0020}', '\u{e007f}') - ]; - - pub const Coptic_table: &'static [(char, char)] = &[ - ('\u{3e2}', '\u{3ef}'), ('\u{2c80}', '\u{2ce4}'), ('\u{2ce5}', '\u{2cea}'), ('\u{2ceb}', - '\u{2cee}'), ('\u{2cef}', '\u{2cf1}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2cf9}', '\u{2cfc}'), - ('\u{2cfd}', '\u{2cfd}'), ('\u{2cfe}', '\u{2cff}') - ]; - - pub const Cuneiform_table: &'static [(char, char)] = &[ - ('\u{12000}', '\u{12398}'), ('\u{12400}', '\u{1246e}'), ('\u{12470}', '\u{12474}') - ]; - - pub const Cypriot_table: &'static [(char, char)] = &[ - ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', '\u{10835}'), - ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', '\u{1083f}') - ]; - - pub const Cyrillic_table: &'static [(char, char)] = &[ - ('\u{400}', '\u{481}'), ('\u{482}', '\u{482}'), ('\u{483}', '\u{484}'), ('\u{487}', - '\u{487}'), ('\u{488}', '\u{489}'), ('\u{48a}', '\u{52f}'), ('\u{1d2b}', '\u{1d2b}'), - ('\u{1d78}', '\u{1d78}'), ('\u{2de0}', '\u{2dff}'), ('\u{a640}', '\u{a66d}'), ('\u{a66e}', - '\u{a66e}'), ('\u{a66f}', '\u{a66f}'), ('\u{a670}', '\u{a672}'), ('\u{a673}', '\u{a673}'), - ('\u{a674}', '\u{a67d}'), ('\u{a67e}', '\u{a67e}'), ('\u{a67f}', '\u{a67f}'), ('\u{a680}', - '\u{a69b}'), ('\u{a69c}', '\u{a69d}'), ('\u{a69f}', '\u{a69f}') - ]; - - pub const Deseret_table: &'static [(char, char)] = &[ - ('\u{10400}', '\u{1044f}') - ]; - - pub const Devanagari_table: &'static [(char, char)] = &[ - ('\u{900}', '\u{902}'), ('\u{903}', '\u{903}'), ('\u{904}', '\u{939}'), ('\u{93a}', - '\u{93a}'), ('\u{93b}', '\u{93b}'), ('\u{93c}', '\u{93c}'), ('\u{93d}', '\u{93d}'), - ('\u{93e}', '\u{940}'), ('\u{941}', '\u{948}'), ('\u{949}', '\u{94c}'), ('\u{94d}', - '\u{94d}'), ('\u{94e}', '\u{94f}'), ('\u{950}', '\u{950}'), ('\u{953}', '\u{957}'), - ('\u{958}', '\u{961}'), ('\u{962}', '\u{963}'), ('\u{966}', '\u{96f}'), ('\u{970}', - '\u{970}'), ('\u{971}', '\u{971}'), ('\u{972}', '\u{97f}'), ('\u{a8e0}', '\u{a8f1}'), - ('\u{a8f2}', '\u{a8f7}'), ('\u{a8f8}', '\u{a8fa}'), ('\u{a8fb}', '\u{a8fb}') - ]; - - pub const Duployan_table: &'static [(char, char)] = &[ - ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), - ('\u{1bc90}', '\u{1bc99}'), ('\u{1bc9c}', '\u{1bc9c}'), ('\u{1bc9d}', '\u{1bc9e}'), - ('\u{1bc9f}', '\u{1bc9f}') - ]; - - pub const Egyptian_Hieroglyphs_table: &'static [(char, char)] = &[ - ('\u{13000}', '\u{1342e}') - ]; - - pub const Elbasan_table: &'static [(char, char)] = &[ - ('\u{10500}', '\u{10527}') - ]; - - pub const Ethiopic_table: &'static [(char, char)] = &[ - ('\u{1200}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', - '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), - ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', - '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), - ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{135d}', '\u{135f}'), ('\u{1360}', - '\u{1368}'), ('\u{1369}', '\u{137c}'), ('\u{1380}', '\u{138f}'), ('\u{1390}', '\u{1399}'), - ('\u{2d80}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', - '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), - ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', - '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}') - ]; - - pub const Georgian_table: &'static [(char, char)] = &[ - ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', - '\u{10fa}'), ('\u{10fc}', '\u{10fc}'), ('\u{10fd}', '\u{10ff}'), ('\u{2d00}', '\u{2d25}'), - ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}') - ]; - - pub const Glagolitic_table: &'static [(char, char)] = &[ - ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}') - ]; - - pub const Gothic_table: &'static [(char, char)] = &[ - ('\u{10330}', '\u{10340}'), ('\u{10341}', '\u{10341}'), ('\u{10342}', '\u{10349}'), - ('\u{1034a}', '\u{1034a}') - ]; - - pub const Grantha_table: &'static [(char, char)] = &[ - ('\u{11301}', '\u{11301}'), ('\u{11302}', '\u{11303}'), ('\u{11305}', '\u{1130c}'), - ('\u{1130f}', '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), - ('\u{11332}', '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133c}', '\u{1133c}'), - ('\u{1133d}', '\u{1133d}'), ('\u{1133e}', '\u{1133f}'), ('\u{11340}', '\u{11340}'), - ('\u{11341}', '\u{11344}'), ('\u{11347}', '\u{11348}'), ('\u{1134b}', '\u{1134d}'), - ('\u{11357}', '\u{11357}'), ('\u{1135d}', '\u{11361}'), ('\u{11362}', '\u{11363}'), - ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}') - ]; - - pub const Greek_table: &'static [(char, char)] = &[ - ('\u{370}', '\u{373}'), ('\u{375}', '\u{375}'), ('\u{376}', '\u{377}'), ('\u{37a}', - '\u{37a}'), ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{384}', '\u{384}'), - ('\u{386}', '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', - '\u{3a1}'), ('\u{3a3}', '\u{3e1}'), ('\u{3f0}', '\u{3f5}'), ('\u{3f6}', '\u{3f6}'), - ('\u{3f7}', '\u{3ff}'), ('\u{1d26}', '\u{1d2a}'), ('\u{1d5d}', '\u{1d61}'), ('\u{1d66}', - '\u{1d6a}'), ('\u{1dbf}', '\u{1dbf}'), ('\u{1f00}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), - ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', - '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), - ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbd}', '\u{1fbd}'), ('\u{1fbe}', - '\u{1fbe}'), ('\u{1fbf}', '\u{1fc1}'), ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), - ('\u{1fcd}', '\u{1fcf}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fdd}', - '\u{1fdf}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1fed}', '\u{1fef}'), ('\u{1ff2}', '\u{1ff4}'), - ('\u{1ff6}', '\u{1ffc}'), ('\u{1ffd}', '\u{1ffe}'), ('\u{2126}', '\u{2126}'), ('\u{ab65}', - '\u{ab65}'), ('\u{10140}', '\u{10174}'), ('\u{10175}', '\u{10178}'), ('\u{10179}', - '\u{10189}'), ('\u{1018a}', '\u{1018b}'), ('\u{1018c}', '\u{1018c}'), ('\u{101a0}', - '\u{101a0}'), ('\u{1d200}', '\u{1d241}'), ('\u{1d242}', '\u{1d244}'), ('\u{1d245}', - '\u{1d245}') - ]; - - pub const Gujarati_table: &'static [(char, char)] = &[ - ('\u{a81}', '\u{a82}'), ('\u{a83}', '\u{a83}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', - '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), - ('\u{ab5}', '\u{ab9}'), ('\u{abc}', '\u{abc}'), ('\u{abd}', '\u{abd}'), ('\u{abe}', - '\u{ac0}'), ('\u{ac1}', '\u{ac5}'), ('\u{ac7}', '\u{ac8}'), ('\u{ac9}', '\u{ac9}'), - ('\u{acb}', '\u{acc}'), ('\u{acd}', '\u{acd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', - '\u{ae1}'), ('\u{ae2}', '\u{ae3}'), ('\u{ae6}', '\u{aef}'), ('\u{af0}', '\u{af0}'), - ('\u{af1}', '\u{af1}') - ]; - - pub const Gurmukhi_table: &'static [(char, char)] = &[ - ('\u{a01}', '\u{a02}'), ('\u{a03}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', - '\u{a10}'), ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), - ('\u{a35}', '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3c}', '\u{a3c}'), ('\u{a3e}', - '\u{a40}'), ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), - ('\u{a51}', '\u{a51}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a66}', - '\u{a6f}'), ('\u{a70}', '\u{a71}'), ('\u{a72}', '\u{a74}'), ('\u{a75}', '\u{a75}') - ]; - - pub const Han_table: &'static [(char, char)] = &[ - ('\u{2e80}', '\u{2e99}'), ('\u{2e9b}', '\u{2ef3}'), ('\u{2f00}', '\u{2fd5}'), ('\u{3005}', - '\u{3005}'), ('\u{3007}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3038}', '\u{303a}'), - ('\u{303b}', '\u{303b}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fcc}'), ('\u{f900}', - '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', - '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', '\u{2fa1d}') - ]; - - pub const Hangul_table: &'static [(char, char)] = &[ - ('\u{1100}', '\u{11ff}'), ('\u{302e}', '\u{302f}'), ('\u{3131}', '\u{318e}'), ('\u{3200}', - '\u{321e}'), ('\u{3260}', '\u{327e}'), ('\u{a960}', '\u{a97c}'), ('\u{ac00}', '\u{d7a3}'), - ('\u{d7b0}', '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{ffa0}', '\u{ffbe}'), ('\u{ffc2}', - '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}') - ]; - - pub const Hanunoo_table: &'static [(char, char)] = &[ - ('\u{1720}', '\u{1731}'), ('\u{1732}', '\u{1734}') - ]; - - pub const Hebrew_table: &'static [(char, char)] = &[ - ('\u{591}', '\u{5bd}'), ('\u{5be}', '\u{5be}'), ('\u{5bf}', '\u{5bf}'), ('\u{5c0}', - '\u{5c0}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c3}', '\u{5c3}'), ('\u{5c4}', '\u{5c5}'), - ('\u{5c6}', '\u{5c6}'), ('\u{5c7}', '\u{5c7}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', - '\u{5f2}'), ('\u{5f3}', '\u{5f4}'), ('\u{fb1d}', '\u{fb1d}'), ('\u{fb1e}', '\u{fb1e}'), - ('\u{fb1f}', '\u{fb28}'), ('\u{fb29}', '\u{fb29}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', - '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), - ('\u{fb46}', '\u{fb4f}') - ]; - - pub const Hiragana_table: &'static [(char, char)] = &[ - ('\u{3041}', '\u{3096}'), ('\u{309d}', '\u{309e}'), ('\u{309f}', '\u{309f}'), ('\u{1b001}', - '\u{1b001}'), ('\u{1f200}', '\u{1f200}') - ]; - - pub const Imperial_Aramaic_table: &'static [(char, char)] = &[ - ('\u{10840}', '\u{10855}'), ('\u{10857}', '\u{10857}'), ('\u{10858}', '\u{1085f}') - ]; - - pub const Inherited_table: &'static [(char, char)] = &[ - ('\u{300}', '\u{36f}'), ('\u{485}', '\u{486}'), ('\u{64b}', '\u{655}'), ('\u{670}', - '\u{670}'), ('\u{951}', '\u{952}'), ('\u{1ab0}', '\u{1abd}'), ('\u{1abe}', '\u{1abe}'), - ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1ce0}'), ('\u{1ce2}', '\u{1ce8}'), ('\u{1ced}', - '\u{1ced}'), ('\u{1cf4}', '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), ('\u{1dc0}', '\u{1df5}'), - ('\u{1dfc}', '\u{1dff}'), ('\u{200c}', '\u{200d}'), ('\u{20d0}', '\u{20dc}'), ('\u{20dd}', - '\u{20e0}'), ('\u{20e1}', '\u{20e1}'), ('\u{20e2}', '\u{20e4}'), ('\u{20e5}', '\u{20f0}'), - ('\u{302a}', '\u{302d}'), ('\u{3099}', '\u{309a}'), ('\u{fe00}', '\u{fe0f}'), ('\u{fe20}', - '\u{fe2d}'), ('\u{101fd}', '\u{101fd}'), ('\u{102e0}', '\u{102e0}'), ('\u{1d167}', - '\u{1d169}'), ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', - '\u{1d1ad}'), ('\u{e0100}', '\u{e01ef}') - ]; - - pub const Inscriptional_Pahlavi_table: &'static [(char, char)] = &[ - ('\u{10b60}', '\u{10b72}'), ('\u{10b78}', '\u{10b7f}') - ]; - - pub const Inscriptional_Parthian_table: &'static [(char, char)] = &[ - ('\u{10b40}', '\u{10b55}'), ('\u{10b58}', '\u{10b5f}') - ]; - - pub const Javanese_table: &'static [(char, char)] = &[ - ('\u{a980}', '\u{a982}'), ('\u{a983}', '\u{a983}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9b3}', - '\u{a9b3}'), ('\u{a9b4}', '\u{a9b5}'), ('\u{a9b6}', '\u{a9b9}'), ('\u{a9ba}', '\u{a9bb}'), - ('\u{a9bc}', '\u{a9bc}'), ('\u{a9bd}', '\u{a9c0}'), ('\u{a9c1}', '\u{a9cd}'), ('\u{a9d0}', - '\u{a9d9}'), ('\u{a9de}', '\u{a9df}') - ]; - - pub const Kaithi_table: &'static [(char, char)] = &[ - ('\u{11080}', '\u{11081}'), ('\u{11082}', '\u{11082}'), ('\u{11083}', '\u{110af}'), - ('\u{110b0}', '\u{110b2}'), ('\u{110b3}', '\u{110b6}'), ('\u{110b7}', '\u{110b8}'), - ('\u{110b9}', '\u{110ba}'), ('\u{110bb}', '\u{110bc}'), ('\u{110bd}', '\u{110bd}'), - ('\u{110be}', '\u{110c1}') - ]; - - pub const Kannada_table: &'static [(char, char)] = &[ - ('\u{c81}', '\u{c81}'), ('\u{c82}', '\u{c83}'), ('\u{c85}', '\u{c8c}'), ('\u{c8e}', - '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), - ('\u{cbc}', '\u{cbc}'), ('\u{cbd}', '\u{cbd}'), ('\u{cbe}', '\u{cbe}'), ('\u{cbf}', - '\u{cbf}'), ('\u{cc0}', '\u{cc4}'), ('\u{cc6}', '\u{cc6}'), ('\u{cc7}', '\u{cc8}'), - ('\u{cca}', '\u{ccb}'), ('\u{ccc}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', - '\u{cde}'), ('\u{ce0}', '\u{ce1}'), ('\u{ce2}', '\u{ce3}'), ('\u{ce6}', '\u{cef}'), - ('\u{cf1}', '\u{cf2}') - ]; - - pub const Katakana_table: &'static [(char, char)] = &[ - ('\u{30a1}', '\u{30fa}'), ('\u{30fd}', '\u{30fe}'), ('\u{30ff}', '\u{30ff}'), ('\u{31f0}', - '\u{31ff}'), ('\u{32d0}', '\u{32fe}'), ('\u{3300}', '\u{3357}'), ('\u{ff66}', '\u{ff6f}'), - ('\u{ff71}', '\u{ff9d}'), ('\u{1b000}', '\u{1b000}') - ]; - - pub const Kayah_Li_table: &'static [(char, char)] = &[ - ('\u{a900}', '\u{a909}'), ('\u{a90a}', '\u{a925}'), ('\u{a926}', '\u{a92d}'), ('\u{a92f}', - '\u{a92f}') - ]; - - pub const Kharoshthi_table: &'static [(char, char)] = &[ - ('\u{10a00}', '\u{10a00}'), ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), - ('\u{10a0c}', '\u{10a0f}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), - ('\u{10a19}', '\u{10a33}'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), - ('\u{10a40}', '\u{10a47}'), ('\u{10a50}', '\u{10a58}') - ]; - - pub const Khmer_table: &'static [(char, char)] = &[ - ('\u{1780}', '\u{17b3}'), ('\u{17b4}', '\u{17b5}'), ('\u{17b6}', '\u{17b6}'), ('\u{17b7}', - '\u{17bd}'), ('\u{17be}', '\u{17c5}'), ('\u{17c6}', '\u{17c6}'), ('\u{17c7}', '\u{17c8}'), - ('\u{17c9}', '\u{17d3}'), ('\u{17d4}', '\u{17d6}'), ('\u{17d7}', '\u{17d7}'), ('\u{17d8}', - '\u{17da}'), ('\u{17db}', '\u{17db}'), ('\u{17dc}', '\u{17dc}'), ('\u{17dd}', '\u{17dd}'), - ('\u{17e0}', '\u{17e9}'), ('\u{17f0}', '\u{17f9}'), ('\u{19e0}', '\u{19ff}') - ]; - - pub const Khojki_table: &'static [(char, char)] = &[ - ('\u{11200}', '\u{11211}'), ('\u{11213}', '\u{1122b}'), ('\u{1122c}', '\u{1122e}'), - ('\u{1122f}', '\u{11231}'), ('\u{11232}', '\u{11233}'), ('\u{11234}', '\u{11234}'), - ('\u{11235}', '\u{11235}'), ('\u{11236}', '\u{11237}'), ('\u{11238}', '\u{1123d}') - ]; - - pub const Khudawadi_table: &'static [(char, char)] = &[ - ('\u{112b0}', '\u{112de}'), ('\u{112df}', '\u{112df}'), ('\u{112e0}', '\u{112e2}'), - ('\u{112e3}', '\u{112ea}'), ('\u{112f0}', '\u{112f9}') - ]; - - pub const Lao_table: &'static [(char, char)] = &[ - ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', - '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), - ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', - '\u{eab}'), ('\u{ead}', '\u{eb0}'), ('\u{eb1}', '\u{eb1}'), ('\u{eb2}', '\u{eb3}'), - ('\u{eb4}', '\u{eb9}'), ('\u{ebb}', '\u{ebc}'), ('\u{ebd}', '\u{ebd}'), ('\u{ec0}', - '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{ec8}', '\u{ecd}'), ('\u{ed0}', '\u{ed9}'), - ('\u{edc}', '\u{edf}') - ]; - - pub const Latin_table: &'static [(char, char)] = &[ - ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{ba}', '\u{ba}'), - ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'), ('\u{1bb}', '\u{1bb}'), - ('\u{1bc}', '\u{1bf}'), ('\u{1c0}', '\u{1c3}'), ('\u{1c4}', '\u{293}'), ('\u{294}', - '\u{294}'), ('\u{295}', '\u{2af}'), ('\u{2b0}', '\u{2b8}'), ('\u{2e0}', '\u{2e4}'), - ('\u{1d00}', '\u{1d25}'), ('\u{1d2c}', '\u{1d5c}'), ('\u{1d62}', '\u{1d65}'), ('\u{1d6b}', - '\u{1d77}'), ('\u{1d79}', '\u{1d9a}'), ('\u{1d9b}', '\u{1dbe}'), ('\u{1e00}', '\u{1eff}'), - ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{212a}', - '\u{212b}'), ('\u{2132}', '\u{2132}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2182}'), - ('\u{2183}', '\u{2184}'), ('\u{2185}', '\u{2188}'), ('\u{2c60}', '\u{2c7b}'), ('\u{2c7c}', - '\u{2c7d}'), ('\u{2c7e}', '\u{2c7f}'), ('\u{a722}', '\u{a76f}'), ('\u{a770}', '\u{a770}'), - ('\u{a771}', '\u{a787}'), ('\u{a78b}', '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', - '\u{a7b1}'), ('\u{a7f7}', '\u{a7f7}'), ('\u{a7f8}', '\u{a7f9}'), ('\u{a7fa}', '\u{a7fa}'), - ('\u{a7fb}', '\u{a7ff}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab5f}'), ('\u{ab64}', - '\u{ab64}'), ('\u{fb00}', '\u{fb06}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}') - ]; - - pub const Lepcha_table: &'static [(char, char)] = &[ - ('\u{1c00}', '\u{1c23}'), ('\u{1c24}', '\u{1c2b}'), ('\u{1c2c}', '\u{1c33}'), ('\u{1c34}', - '\u{1c35}'), ('\u{1c36}', '\u{1c37}'), ('\u{1c3b}', '\u{1c3f}'), ('\u{1c40}', '\u{1c49}'), - ('\u{1c4d}', '\u{1c4f}') - ]; - - pub const Limbu_table: &'static [(char, char)] = &[ - ('\u{1900}', '\u{191e}'), ('\u{1920}', '\u{1922}'), ('\u{1923}', '\u{1926}'), ('\u{1927}', - '\u{1928}'), ('\u{1929}', '\u{192b}'), ('\u{1930}', '\u{1931}'), ('\u{1932}', '\u{1932}'), - ('\u{1933}', '\u{1938}'), ('\u{1939}', '\u{193b}'), ('\u{1940}', '\u{1940}'), ('\u{1944}', - '\u{1945}'), ('\u{1946}', '\u{194f}') - ]; - - pub const Linear_A_table: &'static [(char, char)] = &[ - ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', '\u{10767}') - ]; - - pub const Linear_B_table: &'static [(char, char)] = &[ - ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), - ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), - ('\u{10080}', '\u{100fa}') - ]; - - pub const Lisu_table: &'static [(char, char)] = &[ - ('\u{a4d0}', '\u{a4f7}'), ('\u{a4f8}', '\u{a4fd}'), ('\u{a4fe}', '\u{a4ff}') - ]; - - pub const Lycian_table: &'static [(char, char)] = &[ - ('\u{10280}', '\u{1029c}') - ]; - - pub const Lydian_table: &'static [(char, char)] = &[ - ('\u{10920}', '\u{10939}'), ('\u{1093f}', '\u{1093f}') - ]; - - pub const Mahajani_table: &'static [(char, char)] = &[ - ('\u{11150}', '\u{11172}'), ('\u{11173}', '\u{11173}'), ('\u{11174}', '\u{11175}'), - ('\u{11176}', '\u{11176}') - ]; - - pub const Malayalam_table: &'static [(char, char)] = &[ - ('\u{d01}', '\u{d01}'), ('\u{d02}', '\u{d03}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', - '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d3e}', '\u{d40}'), - ('\u{d41}', '\u{d44}'), ('\u{d46}', '\u{d48}'), ('\u{d4a}', '\u{d4c}'), ('\u{d4d}', - '\u{d4d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d57}', '\u{d57}'), ('\u{d60}', '\u{d61}'), - ('\u{d62}', '\u{d63}'), ('\u{d66}', '\u{d6f}'), ('\u{d70}', '\u{d75}'), ('\u{d79}', - '\u{d79}'), ('\u{d7a}', '\u{d7f}') - ]; - - pub const Mandaic_table: &'static [(char, char)] = &[ - ('\u{840}', '\u{858}'), ('\u{859}', '\u{85b}'), ('\u{85e}', '\u{85e}') - ]; - - pub const Manichaean_table: &'static [(char, char)] = &[ - ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac8}', '\u{10ac8}'), ('\u{10ac9}', '\u{10ae4}'), - ('\u{10ae5}', '\u{10ae6}'), ('\u{10aeb}', '\u{10aef}'), ('\u{10af0}', '\u{10af6}') - ]; - - pub const Meetei_Mayek_table: &'static [(char, char)] = &[ - ('\u{aae0}', '\u{aaea}'), ('\u{aaeb}', '\u{aaeb}'), ('\u{aaec}', '\u{aaed}'), ('\u{aaee}', - '\u{aaef}'), ('\u{aaf0}', '\u{aaf1}'), ('\u{aaf2}', '\u{aaf2}'), ('\u{aaf3}', '\u{aaf4}'), - ('\u{aaf5}', '\u{aaf5}'), ('\u{aaf6}', '\u{aaf6}'), ('\u{abc0}', '\u{abe2}'), ('\u{abe3}', - '\u{abe4}'), ('\u{abe5}', '\u{abe5}'), ('\u{abe6}', '\u{abe7}'), ('\u{abe8}', '\u{abe8}'), - ('\u{abe9}', '\u{abea}'), ('\u{abeb}', '\u{abeb}'), ('\u{abec}', '\u{abec}'), ('\u{abed}', - '\u{abed}'), ('\u{abf0}', '\u{abf9}') - ]; - - pub const Mende_Kikakui_table: &'static [(char, char)] = &[ - ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8c7}', '\u{1e8cf}'), ('\u{1e8d0}', '\u{1e8d6}') - ]; - - pub const Meroitic_Cursive_table: &'static [(char, char)] = &[ - ('\u{109a0}', '\u{109b7}'), ('\u{109be}', '\u{109bf}') - ]; - - pub const Meroitic_Hieroglyphs_table: &'static [(char, char)] = &[ - ('\u{10980}', '\u{1099f}') - ]; - - pub const Miao_table: &'static [(char, char)] = &[ - ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{16f51}', '\u{16f7e}'), - ('\u{16f8f}', '\u{16f92}'), ('\u{16f93}', '\u{16f9f}') - ]; - - pub const Modi_table: &'static [(char, char)] = &[ - ('\u{11600}', '\u{1162f}'), ('\u{11630}', '\u{11632}'), ('\u{11633}', '\u{1163a}'), - ('\u{1163b}', '\u{1163c}'), ('\u{1163d}', '\u{1163d}'), ('\u{1163e}', '\u{1163e}'), - ('\u{1163f}', '\u{11640}'), ('\u{11641}', '\u{11643}'), ('\u{11644}', '\u{11644}'), - ('\u{11650}', '\u{11659}') - ]; - - pub const Mongolian_table: &'static [(char, char)] = &[ - ('\u{1800}', '\u{1801}'), ('\u{1804}', '\u{1804}'), ('\u{1806}', '\u{1806}'), ('\u{1807}', - '\u{180a}'), ('\u{180b}', '\u{180d}'), ('\u{180e}', '\u{180e}'), ('\u{1810}', '\u{1819}'), - ('\u{1820}', '\u{1842}'), ('\u{1843}', '\u{1843}'), ('\u{1844}', '\u{1877}'), ('\u{1880}', - '\u{18a8}'), ('\u{18a9}', '\u{18a9}'), ('\u{18aa}', '\u{18aa}') - ]; - - pub const Mro_table: &'static [(char, char)] = &[ - ('\u{16a40}', '\u{16a5e}'), ('\u{16a60}', '\u{16a69}'), ('\u{16a6e}', '\u{16a6f}') - ]; - - pub const Myanmar_table: &'static [(char, char)] = &[ - ('\u{1000}', '\u{102a}'), ('\u{102b}', '\u{102c}'), ('\u{102d}', '\u{1030}'), ('\u{1031}', - '\u{1031}'), ('\u{1032}', '\u{1037}'), ('\u{1038}', '\u{1038}'), ('\u{1039}', '\u{103a}'), - ('\u{103b}', '\u{103c}'), ('\u{103d}', '\u{103e}'), ('\u{103f}', '\u{103f}'), ('\u{1040}', - '\u{1049}'), ('\u{104a}', '\u{104f}'), ('\u{1050}', '\u{1055}'), ('\u{1056}', '\u{1057}'), - ('\u{1058}', '\u{1059}'), ('\u{105a}', '\u{105d}'), ('\u{105e}', '\u{1060}'), ('\u{1061}', - '\u{1061}'), ('\u{1062}', '\u{1064}'), ('\u{1065}', '\u{1066}'), ('\u{1067}', '\u{106d}'), - ('\u{106e}', '\u{1070}'), ('\u{1071}', '\u{1074}'), ('\u{1075}', '\u{1081}'), ('\u{1082}', - '\u{1082}'), ('\u{1083}', '\u{1084}'), ('\u{1085}', '\u{1086}'), ('\u{1087}', '\u{108c}'), - ('\u{108d}', '\u{108d}'), ('\u{108e}', '\u{108e}'), ('\u{108f}', '\u{108f}'), ('\u{1090}', - '\u{1099}'), ('\u{109a}', '\u{109c}'), ('\u{109d}', '\u{109d}'), ('\u{109e}', '\u{109f}'), - ('\u{a9e0}', '\u{a9e4}'), ('\u{a9e5}', '\u{a9e5}'), ('\u{a9e6}', '\u{a9e6}'), ('\u{a9e7}', - '\u{a9ef}'), ('\u{a9f0}', '\u{a9f9}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa60}', '\u{aa6f}'), - ('\u{aa70}', '\u{aa70}'), ('\u{aa71}', '\u{aa76}'), ('\u{aa77}', '\u{aa79}'), ('\u{aa7a}', - '\u{aa7a}'), ('\u{aa7b}', '\u{aa7b}'), ('\u{aa7c}', '\u{aa7c}'), ('\u{aa7d}', '\u{aa7d}'), - ('\u{aa7e}', '\u{aa7f}') - ]; - - pub const Nabataean_table: &'static [(char, char)] = &[ - ('\u{10880}', '\u{1089e}'), ('\u{108a7}', '\u{108af}') - ]; - - pub const New_Tai_Lue_table: &'static [(char, char)] = &[ - ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c0}'), ('\u{19c1}', '\u{19c7}'), ('\u{19c8}', - '\u{19c9}'), ('\u{19d0}', '\u{19d9}'), ('\u{19da}', '\u{19da}'), ('\u{19de}', '\u{19df}') - ]; - - pub const Nko_table: &'static [(char, char)] = &[ - ('\u{7c0}', '\u{7c9}'), ('\u{7ca}', '\u{7ea}'), ('\u{7eb}', '\u{7f3}'), ('\u{7f4}', - '\u{7f5}'), ('\u{7f6}', '\u{7f6}'), ('\u{7f7}', '\u{7f9}'), ('\u{7fa}', '\u{7fa}') - ]; - - pub const Ogham_table: &'static [(char, char)] = &[ - ('\u{1680}', '\u{1680}'), ('\u{1681}', '\u{169a}'), ('\u{169b}', '\u{169b}'), ('\u{169c}', - '\u{169c}') - ]; - - pub const Ol_Chiki_table: &'static [(char, char)] = &[ - ('\u{1c50}', '\u{1c59}'), ('\u{1c5a}', '\u{1c77}'), ('\u{1c78}', '\u{1c7d}'), ('\u{1c7e}', - '\u{1c7f}') - ]; - - pub const Old_Italic_table: &'static [(char, char)] = &[ - ('\u{10300}', '\u{1031f}'), ('\u{10320}', '\u{10323}') - ]; - - pub const Old_North_Arabian_table: &'static [(char, char)] = &[ - ('\u{10a80}', '\u{10a9c}'), ('\u{10a9d}', '\u{10a9f}') - ]; - - pub const Old_Permic_table: &'static [(char, char)] = &[ - ('\u{10350}', '\u{10375}'), ('\u{10376}', '\u{1037a}') - ]; - - pub const Old_Persian_table: &'static [(char, char)] = &[ - ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d0}', '\u{103d0}'), - ('\u{103d1}', '\u{103d5}') - ]; - - pub const Old_South_Arabian_table: &'static [(char, char)] = &[ - ('\u{10a60}', '\u{10a7c}'), ('\u{10a7d}', '\u{10a7e}'), ('\u{10a7f}', '\u{10a7f}') - ]; - - pub const Old_Turkic_table: &'static [(char, char)] = &[ - ('\u{10c00}', '\u{10c48}') - ]; - - pub const Oriya_table: &'static [(char, char)] = &[ - ('\u{b01}', '\u{b01}'), ('\u{b02}', '\u{b03}'), ('\u{b05}', '\u{b0c}'), ('\u{b0f}', - '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', '\u{b33}'), - ('\u{b35}', '\u{b39}'), ('\u{b3c}', '\u{b3c}'), ('\u{b3d}', '\u{b3d}'), ('\u{b3e}', - '\u{b3e}'), ('\u{b3f}', '\u{b3f}'), ('\u{b40}', '\u{b40}'), ('\u{b41}', '\u{b44}'), - ('\u{b47}', '\u{b48}'), ('\u{b4b}', '\u{b4c}'), ('\u{b4d}', '\u{b4d}'), ('\u{b56}', - '\u{b56}'), ('\u{b57}', '\u{b57}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', '\u{b61}'), - ('\u{b62}', '\u{b63}'), ('\u{b66}', '\u{b6f}'), ('\u{b70}', '\u{b70}'), ('\u{b71}', - '\u{b71}'), ('\u{b72}', '\u{b77}') - ]; - - pub const Osmanya_table: &'static [(char, char)] = &[ - ('\u{10480}', '\u{1049d}'), ('\u{104a0}', '\u{104a9}') - ]; - - pub const Pahawh_Hmong_table: &'static [(char, char)] = &[ - ('\u{16b00}', '\u{16b2f}'), ('\u{16b30}', '\u{16b36}'), ('\u{16b37}', '\u{16b3b}'), - ('\u{16b3c}', '\u{16b3f}'), ('\u{16b40}', '\u{16b43}'), ('\u{16b44}', '\u{16b44}'), - ('\u{16b45}', '\u{16b45}'), ('\u{16b50}', '\u{16b59}'), ('\u{16b5b}', '\u{16b61}'), - ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}') - ]; - - pub const Palmyrene_table: &'static [(char, char)] = &[ - ('\u{10860}', '\u{10876}'), ('\u{10877}', '\u{10878}'), ('\u{10879}', '\u{1087f}') - ]; - - pub const Pau_Cin_Hau_table: &'static [(char, char)] = &[ - ('\u{11ac0}', '\u{11af8}') - ]; - - pub const Phags_Pa_table: &'static [(char, char)] = &[ - ('\u{a840}', '\u{a873}'), ('\u{a874}', '\u{a877}') - ]; - - pub const Phoenician_table: &'static [(char, char)] = &[ - ('\u{10900}', '\u{10915}'), ('\u{10916}', '\u{1091b}'), ('\u{1091f}', '\u{1091f}') - ]; - - pub const Psalter_Pahlavi_table: &'static [(char, char)] = &[ - ('\u{10b80}', '\u{10b91}'), ('\u{10b99}', '\u{10b9c}'), ('\u{10ba9}', '\u{10baf}') - ]; - - pub const Rejang_table: &'static [(char, char)] = &[ - ('\u{a930}', '\u{a946}'), ('\u{a947}', '\u{a951}'), ('\u{a952}', '\u{a953}'), ('\u{a95f}', - '\u{a95f}') - ]; - - pub const Runic_table: &'static [(char, char)] = &[ - ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f0}'), ('\u{16f1}', '\u{16f8}') - ]; - - pub const Samaritan_table: &'static [(char, char)] = &[ - ('\u{800}', '\u{815}'), ('\u{816}', '\u{819}'), ('\u{81a}', '\u{81a}'), ('\u{81b}', - '\u{823}'), ('\u{824}', '\u{824}'), ('\u{825}', '\u{827}'), ('\u{828}', '\u{828}'), - ('\u{829}', '\u{82d}'), ('\u{830}', '\u{83e}') - ]; - - pub const Saurashtra_table: &'static [(char, char)] = &[ - ('\u{a880}', '\u{a881}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8b4}', '\u{a8c3}'), ('\u{a8c4}', - '\u{a8c4}'), ('\u{a8ce}', '\u{a8cf}'), ('\u{a8d0}', '\u{a8d9}') - ]; - - pub const Sharada_table: &'static [(char, char)] = &[ - ('\u{11180}', '\u{11181}'), ('\u{11182}', '\u{11182}'), ('\u{11183}', '\u{111b2}'), - ('\u{111b3}', '\u{111b5}'), ('\u{111b6}', '\u{111be}'), ('\u{111bf}', '\u{111c0}'), - ('\u{111c1}', '\u{111c4}'), ('\u{111c5}', '\u{111c8}'), ('\u{111cd}', '\u{111cd}'), - ('\u{111d0}', '\u{111d9}'), ('\u{111da}', '\u{111da}') - ]; - - pub const Shavian_table: &'static [(char, char)] = &[ - ('\u{10450}', '\u{1047f}') - ]; - - pub const Siddham_table: &'static [(char, char)] = &[ - ('\u{11580}', '\u{115ae}'), ('\u{115af}', '\u{115b1}'), ('\u{115b2}', '\u{115b5}'), - ('\u{115b8}', '\u{115bb}'), ('\u{115bc}', '\u{115bd}'), ('\u{115be}', '\u{115be}'), - ('\u{115bf}', '\u{115c0}'), ('\u{115c1}', '\u{115c9}') - ]; - - pub const Sinhala_table: &'static [(char, char)] = &[ - ('\u{d82}', '\u{d83}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', - '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{dca}', '\u{dca}'), - ('\u{dcf}', '\u{dd1}'), ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('\u{dd8}', - '\u{ddf}'), ('\u{de6}', '\u{def}'), ('\u{df2}', '\u{df3}'), ('\u{df4}', '\u{df4}'), - ('\u{111e1}', '\u{111f4}') - ]; - - pub const Sora_Sompeng_table: &'static [(char, char)] = &[ - ('\u{110d0}', '\u{110e8}'), ('\u{110f0}', '\u{110f9}') - ]; - - pub const Sundanese_table: &'static [(char, char)] = &[ - ('\u{1b80}', '\u{1b81}'), ('\u{1b82}', '\u{1b82}'), ('\u{1b83}', '\u{1ba0}'), ('\u{1ba1}', - '\u{1ba1}'), ('\u{1ba2}', '\u{1ba5}'), ('\u{1ba6}', '\u{1ba7}'), ('\u{1ba8}', '\u{1ba9}'), - ('\u{1baa}', '\u{1baa}'), ('\u{1bab}', '\u{1bad}'), ('\u{1bae}', '\u{1baf}'), ('\u{1bb0}', - '\u{1bb9}'), ('\u{1bba}', '\u{1bbf}'), ('\u{1cc0}', '\u{1cc7}') - ]; - - pub const Syloti_Nagri_table: &'static [(char, char)] = &[ - ('\u{a800}', '\u{a801}'), ('\u{a802}', '\u{a802}'), ('\u{a803}', '\u{a805}'), ('\u{a806}', - '\u{a806}'), ('\u{a807}', '\u{a80a}'), ('\u{a80b}', '\u{a80b}'), ('\u{a80c}', '\u{a822}'), - ('\u{a823}', '\u{a824}'), ('\u{a825}', '\u{a826}'), ('\u{a827}', '\u{a827}'), ('\u{a828}', - '\u{a82b}') - ]; - - pub const Syriac_table: &'static [(char, char)] = &[ - ('\u{700}', '\u{70d}'), ('\u{70f}', '\u{70f}'), ('\u{710}', '\u{710}'), ('\u{711}', - '\u{711}'), ('\u{712}', '\u{72f}'), ('\u{730}', '\u{74a}'), ('\u{74d}', '\u{74f}') - ]; - - pub const Tagalog_table: &'static [(char, char)] = &[ - ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1712}', '\u{1714}') - ]; - - pub const Tagbanwa_table: &'static [(char, char)] = &[ - ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1772}', '\u{1773}') - ]; - - pub const Tai_Le_table: &'static [(char, char)] = &[ - ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}') - ]; - - pub const Tai_Tham_table: &'static [(char, char)] = &[ - ('\u{1a20}', '\u{1a54}'), ('\u{1a55}', '\u{1a55}'), ('\u{1a56}', '\u{1a56}'), ('\u{1a57}', - '\u{1a57}'), ('\u{1a58}', '\u{1a5e}'), ('\u{1a60}', '\u{1a60}'), ('\u{1a61}', '\u{1a61}'), - ('\u{1a62}', '\u{1a62}'), ('\u{1a63}', '\u{1a64}'), ('\u{1a65}', '\u{1a6c}'), ('\u{1a6d}', - '\u{1a72}'), ('\u{1a73}', '\u{1a7c}'), ('\u{1a7f}', '\u{1a7f}'), ('\u{1a80}', '\u{1a89}'), - ('\u{1a90}', '\u{1a99}'), ('\u{1aa0}', '\u{1aa6}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1aa8}', - '\u{1aad}') - ]; - - pub const Tai_Viet_table: &'static [(char, char)] = &[ - ('\u{aa80}', '\u{aaaf}'), ('\u{aab0}', '\u{aab0}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab2}', - '\u{aab4}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab7}', '\u{aab8}'), ('\u{aab9}', '\u{aabd}'), - ('\u{aabe}', '\u{aabf}'), ('\u{aac0}', '\u{aac0}'), ('\u{aac1}', '\u{aac1}'), ('\u{aac2}', - '\u{aac2}'), ('\u{aadb}', '\u{aadc}'), ('\u{aadd}', '\u{aadd}'), ('\u{aade}', '\u{aadf}') - ]; - - pub const Takri_table: &'static [(char, char)] = &[ - ('\u{11680}', '\u{116aa}'), ('\u{116ab}', '\u{116ab}'), ('\u{116ac}', '\u{116ac}'), - ('\u{116ad}', '\u{116ad}'), ('\u{116ae}', '\u{116af}'), ('\u{116b0}', '\u{116b5}'), - ('\u{116b6}', '\u{116b6}'), ('\u{116b7}', '\u{116b7}'), ('\u{116c0}', '\u{116c9}') - ]; - - pub const Tamil_table: &'static [(char, char)] = &[ - ('\u{b82}', '\u{b82}'), ('\u{b83}', '\u{b83}'), ('\u{b85}', '\u{b8a}'), ('\u{b8e}', - '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), - ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), ('\u{ba8}', '\u{baa}'), ('\u{bae}', - '\u{bb9}'), ('\u{bbe}', '\u{bbf}'), ('\u{bc0}', '\u{bc0}'), ('\u{bc1}', '\u{bc2}'), - ('\u{bc6}', '\u{bc8}'), ('\u{bca}', '\u{bcc}'), ('\u{bcd}', '\u{bcd}'), ('\u{bd0}', - '\u{bd0}'), ('\u{bd7}', '\u{bd7}'), ('\u{be6}', '\u{bef}'), ('\u{bf0}', '\u{bf2}'), - ('\u{bf3}', '\u{bf8}'), ('\u{bf9}', '\u{bf9}'), ('\u{bfa}', '\u{bfa}') - ]; - - pub const Telugu_table: &'static [(char, char)] = &[ - ('\u{c00}', '\u{c00}'), ('\u{c01}', '\u{c03}'), ('\u{c05}', '\u{c0c}'), ('\u{c0e}', - '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c3d}'), - ('\u{c3e}', '\u{c40}'), ('\u{c41}', '\u{c44}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', - '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c58}', '\u{c59}'), ('\u{c60}', '\u{c61}'), - ('\u{c62}', '\u{c63}'), ('\u{c66}', '\u{c6f}'), ('\u{c78}', '\u{c7e}'), ('\u{c7f}', - '\u{c7f}') - ]; - - pub const Thaana_table: &'static [(char, char)] = &[ - ('\u{780}', '\u{7a5}'), ('\u{7a6}', '\u{7b0}'), ('\u{7b1}', '\u{7b1}') - ]; - - pub const Thai_table: &'static [(char, char)] = &[ - ('\u{e01}', '\u{e30}'), ('\u{e31}', '\u{e31}'), ('\u{e32}', '\u{e33}'), ('\u{e34}', - '\u{e3a}'), ('\u{e40}', '\u{e45}'), ('\u{e46}', '\u{e46}'), ('\u{e47}', '\u{e4e}'), - ('\u{e4f}', '\u{e4f}'), ('\u{e50}', '\u{e59}'), ('\u{e5a}', '\u{e5b}') - ]; - - pub const Tibetan_table: &'static [(char, char)] = &[ - ('\u{f00}', '\u{f00}'), ('\u{f01}', '\u{f03}'), ('\u{f04}', '\u{f12}'), ('\u{f13}', - '\u{f13}'), ('\u{f14}', '\u{f14}'), ('\u{f15}', '\u{f17}'), ('\u{f18}', '\u{f19}'), - ('\u{f1a}', '\u{f1f}'), ('\u{f20}', '\u{f29}'), ('\u{f2a}', '\u{f33}'), ('\u{f34}', - '\u{f34}'), ('\u{f35}', '\u{f35}'), ('\u{f36}', '\u{f36}'), ('\u{f37}', '\u{f37}'), - ('\u{f38}', '\u{f38}'), ('\u{f39}', '\u{f39}'), ('\u{f3a}', '\u{f3a}'), ('\u{f3b}', - '\u{f3b}'), ('\u{f3c}', '\u{f3c}'), ('\u{f3d}', '\u{f3d}'), ('\u{f3e}', '\u{f3f}'), - ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f71}', '\u{f7e}'), ('\u{f7f}', - '\u{f7f}'), ('\u{f80}', '\u{f84}'), ('\u{f85}', '\u{f85}'), ('\u{f86}', '\u{f87}'), - ('\u{f88}', '\u{f8c}'), ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fbe}', - '\u{fc5}'), ('\u{fc6}', '\u{fc6}'), ('\u{fc7}', '\u{fcc}'), ('\u{fce}', '\u{fcf}'), - ('\u{fd0}', '\u{fd4}'), ('\u{fd9}', '\u{fda}') - ]; - - pub const Tifinagh_table: &'static [(char, char)] = &[ - ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d70}', '\u{2d70}'), ('\u{2d7f}', - '\u{2d7f}') - ]; - - pub const Tirhuta_table: &'static [(char, char)] = &[ - ('\u{11480}', '\u{114af}'), ('\u{114b0}', '\u{114b2}'), ('\u{114b3}', '\u{114b8}'), - ('\u{114b9}', '\u{114b9}'), ('\u{114ba}', '\u{114ba}'), ('\u{114bb}', '\u{114be}'), - ('\u{114bf}', '\u{114c0}'), ('\u{114c1}', '\u{114c1}'), ('\u{114c2}', '\u{114c3}'), - ('\u{114c4}', '\u{114c5}'), ('\u{114c6}', '\u{114c6}'), ('\u{114c7}', '\u{114c7}'), - ('\u{114d0}', '\u{114d9}') - ]; - - pub const Ugaritic_table: &'static [(char, char)] = &[ - ('\u{10380}', '\u{1039d}'), ('\u{1039f}', '\u{1039f}') + ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), + ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), + ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), + ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), + ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), + ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1d7ce}', '\u{1d7ff}'), + ('\u{1e800}', '\u{1e8c4}'), ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1ee00}', '\u{1ee03}'), + ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), + ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), + ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), + ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), + ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), + ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), + ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), + ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), + ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), + ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), + ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', '\u{2a6d6}'), + ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', '\u{2fa1d}'), + ('\u{e0100}', '\u{e01ef}') ]; - pub const Vai_table: &'static [(char, char)] = &[ - ('\u{a500}', '\u{a60b}'), ('\u{a60c}', '\u{a60c}'), ('\u{a60d}', '\u{a60f}'), ('\u{a610}', - '\u{a61f}'), ('\u{a620}', '\u{a629}'), ('\u{a62a}', '\u{a62b}') - ]; + pub fn XID_Continue(c: char) -> bool { + super::bsearch_range_table(c, XID_Continue_table) + } - pub const Warang_Citi_table: &'static [(char, char)] = &[ - ('\u{118a0}', '\u{118df}'), ('\u{118e0}', '\u{118e9}'), ('\u{118ea}', '\u{118f2}'), - ('\u{118ff}', '\u{118ff}') + pub const XID_Start_table: &'static [(char, char)] = &[ + ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), + ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'), + ('\u{1bb}', '\u{1bb}'), ('\u{1bc}', '\u{1bf}'), ('\u{1c0}', '\u{1c3}'), ('\u{1c4}', + '\u{293}'), ('\u{294}', '\u{294}'), ('\u{295}', '\u{2af}'), ('\u{2b0}', '\u{2c1}'), + ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', + '\u{2ee}'), ('\u{370}', '\u{373}'), ('\u{374}', '\u{374}'), ('\u{376}', '\u{377}'), + ('\u{37b}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), ('\u{388}', + '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', '\u{3f5}'), + ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}', '\u{556}'), ('\u{559}', + '\u{559}'), ('\u{561}', '\u{587}'), ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), + ('\u{620}', '\u{63f}'), ('\u{640}', '\u{640}'), ('\u{641}', '\u{64a}'), ('\u{66e}', + '\u{66f}'), ('\u{671}', '\u{6d3}'), ('\u{6d5}', '\u{6d5}'), ('\u{6e5}', '\u{6e6}'), + ('\u{6ee}', '\u{6ef}'), ('\u{6fa}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}', + '\u{710}'), ('\u{712}', '\u{72f}'), ('\u{74d}', '\u{7a5}'), ('\u{7b1}', '\u{7b1}'), + ('\u{7ca}', '\u{7ea}'), ('\u{7f4}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{800}', + '\u{815}'), ('\u{81a}', '\u{81a}'), ('\u{824}', '\u{824}'), ('\u{828}', '\u{828}'), + ('\u{840}', '\u{858}'), ('\u{8a0}', '\u{8b2}'), ('\u{904}', '\u{939}'), ('\u{93d}', + '\u{93d}'), ('\u{950}', '\u{950}'), ('\u{958}', '\u{961}'), ('\u{971}', '\u{971}'), + ('\u{972}', '\u{980}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), ('\u{993}', + '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', '\u{9b9}'), + ('\u{9bd}', '\u{9bd}'), ('\u{9ce}', '\u{9ce}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', + '\u{9e1}'), ('\u{9f0}', '\u{9f1}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), + ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', + '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a59}', '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), + ('\u{a72}', '\u{a74}'), ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', + '\u{aa8}'), ('\u{aaa}', '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), + ('\u{abd}', '\u{abd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', '\u{ae1}'), ('\u{b05}', + '\u{b0c}'), ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), + ('\u{b32}', '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3d}', '\u{b3d}'), ('\u{b5c}', + '\u{b5d}'), ('\u{b5f}', '\u{b61}'), ('\u{b71}', '\u{b71}'), ('\u{b83}', '\u{b83}'), + ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', + '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), + ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bd0}', '\u{bd0}'), ('\u{c05}', + '\u{c0c}'), ('\u{c0e}', '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), + ('\u{c3d}', '\u{c3d}'), ('\u{c58}', '\u{c59}'), ('\u{c60}', '\u{c61}'), ('\u{c85}', + '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', '\u{cb3}'), + ('\u{cb5}', '\u{cb9}'), ('\u{cbd}', '\u{cbd}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', + '\u{ce1}'), ('\u{cf1}', '\u{cf2}'), ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), + ('\u{d12}', '\u{d3a}'), ('\u{d3d}', '\u{d3d}'), ('\u{d4e}', '\u{d4e}'), ('\u{d60}', + '\u{d61}'), ('\u{d7a}', '\u{d7f}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), + ('\u{db3}', '\u{dbb}'), ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{e01}', + '\u{e30}'), ('\u{e32}', '\u{e32}'), ('\u{e40}', '\u{e45}'), ('\u{e46}', '\u{e46}'), + ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), ('\u{e8a}', + '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', '\u{e9f}'), + ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), ('\u{eaa}', + '\u{eab}'), ('\u{ead}', '\u{eb0}'), ('\u{eb2}', '\u{eb2}'), ('\u{ebd}', '\u{ebd}'), + ('\u{ec0}', '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{edc}', '\u{edf}'), ('\u{f00}', + '\u{f00}'), ('\u{f40}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f88}', '\u{f8c}'), + ('\u{1000}', '\u{102a}'), ('\u{103f}', '\u{103f}'), ('\u{1050}', '\u{1055}'), ('\u{105a}', + '\u{105d}'), ('\u{1061}', '\u{1061}'), ('\u{1065}', '\u{1066}'), ('\u{106e}', '\u{1070}'), + ('\u{1075}', '\u{1081}'), ('\u{108e}', '\u{108e}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', + '\u{10c7}'), ('\u{10cd}', '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{10fc}'), + ('\u{10fd}', '\u{1248}'), ('\u{124a}', '\u{124d}'), ('\u{1250}', '\u{1256}'), ('\u{1258}', + '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', '\u{1288}'), ('\u{128a}', '\u{128d}'), + ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), ('\u{12b8}', '\u{12be}'), ('\u{12c0}', + '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', '\u{12d6}'), ('\u{12d8}', '\u{1310}'), + ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', + '\u{13f4}'), ('\u{1401}', '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), + ('\u{16a0}', '\u{16ea}'), ('\u{16ee}', '\u{16f0}'), ('\u{16f1}', '\u{16f8}'), ('\u{1700}', + '\u{170c}'), ('\u{170e}', '\u{1711}'), ('\u{1720}', '\u{1731}'), ('\u{1740}', '\u{1751}'), + ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), ('\u{1780}', '\u{17b3}'), ('\u{17d7}', + '\u{17d7}'), ('\u{17dc}', '\u{17dc}'), ('\u{1820}', '\u{1842}'), ('\u{1843}', '\u{1843}'), + ('\u{1844}', '\u{1877}'), ('\u{1880}', '\u{18a8}'), ('\u{18aa}', '\u{18aa}'), ('\u{18b0}', + '\u{18f5}'), ('\u{1900}', '\u{191e}'), ('\u{1950}', '\u{196d}'), ('\u{1970}', '\u{1974}'), + ('\u{1980}', '\u{19ab}'), ('\u{19c1}', '\u{19c7}'), ('\u{1a00}', '\u{1a16}'), ('\u{1a20}', + '\u{1a54}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1b05}', '\u{1b33}'), ('\u{1b45}', '\u{1b4b}'), + ('\u{1b83}', '\u{1ba0}'), ('\u{1bae}', '\u{1baf}'), ('\u{1bba}', '\u{1be5}'), ('\u{1c00}', + '\u{1c23}'), ('\u{1c4d}', '\u{1c4f}'), ('\u{1c5a}', '\u{1c77}'), ('\u{1c78}', '\u{1c7d}'), + ('\u{1ce9}', '\u{1cec}'), ('\u{1cee}', '\u{1cf1}'), ('\u{1cf5}', '\u{1cf6}'), ('\u{1d00}', + '\u{1d2b}'), ('\u{1d2c}', '\u{1d6a}'), ('\u{1d6b}', '\u{1d77}'), ('\u{1d78}', '\u{1d78}'), + ('\u{1d79}', '\u{1d9a}'), ('\u{1d9b}', '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}', + '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), + ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', + '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), + ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', + '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), + ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}', + '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), + ('\u{2118}', '\u{2118}'), ('\u{2119}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', + '\u{2126}'), ('\u{2128}', '\u{2128}'), ('\u{212a}', '\u{212d}'), ('\u{212e}', '\u{212e}'), + ('\u{212f}', '\u{2134}'), ('\u{2135}', '\u{2138}'), ('\u{2139}', '\u{2139}'), ('\u{213c}', + '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2182}'), + ('\u{2183}', '\u{2184}'), ('\u{2185}', '\u{2188}'), ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', + '\u{2c5e}'), ('\u{2c60}', '\u{2c7b}'), ('\u{2c7c}', '\u{2c7d}'), ('\u{2c7e}', '\u{2ce4}'), + ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', + '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), + ('\u{2d80}', '\u{2d96}'), ('\u{2da0}', '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', + '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), + ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', '\u{2dde}'), ('\u{3005}', '\u{3005}'), ('\u{3006}', + '\u{3006}'), ('\u{3007}', '\u{3007}'), ('\u{3021}', '\u{3029}'), ('\u{3031}', '\u{3035}'), + ('\u{3038}', '\u{303a}'), ('\u{303b}', '\u{303b}'), ('\u{303c}', '\u{303c}'), ('\u{3041}', + '\u{3096}'), ('\u{309d}', '\u{309e}'), ('\u{309f}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), + ('\u{30fc}', '\u{30fe}'), ('\u{30ff}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', + '\u{318e}'), ('\u{31a0}', '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), + ('\u{4e00}', '\u{9fcc}'), ('\u{a000}', '\u{a014}'), ('\u{a015}', '\u{a015}'), ('\u{a016}', + '\u{a48c}'), ('\u{a4d0}', '\u{a4f7}'), ('\u{a4f8}', '\u{a4fd}'), ('\u{a500}', '\u{a60b}'), + ('\u{a60c}', '\u{a60c}'), ('\u{a610}', '\u{a61f}'), ('\u{a62a}', '\u{a62b}'), ('\u{a640}', + '\u{a66d}'), ('\u{a66e}', '\u{a66e}'), ('\u{a67f}', '\u{a67f}'), ('\u{a680}', '\u{a69b}'), + ('\u{a69c}', '\u{a69d}'), ('\u{a6a0}', '\u{a6e5}'), ('\u{a6e6}', '\u{a6ef}'), ('\u{a717}', + '\u{a71f}'), ('\u{a722}', '\u{a76f}'), ('\u{a770}', '\u{a770}'), ('\u{a771}', '\u{a787}'), + ('\u{a788}', '\u{a788}'), ('\u{a78b}', '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', + '\u{a7b1}'), ('\u{a7f7}', '\u{a7f7}'), ('\u{a7f8}', '\u{a7f9}'), ('\u{a7fa}', '\u{a7fa}'), + ('\u{a7fb}', '\u{a801}'), ('\u{a803}', '\u{a805}'), ('\u{a807}', '\u{a80a}'), ('\u{a80c}', + '\u{a822}'), ('\u{a840}', '\u{a873}'), ('\u{a882}', '\u{a8b3}'), ('\u{a8f2}', '\u{a8f7}'), + ('\u{a8fb}', '\u{a8fb}'), ('\u{a90a}', '\u{a925}'), ('\u{a930}', '\u{a946}'), ('\u{a960}', + '\u{a97c}'), ('\u{a984}', '\u{a9b2}'), ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e0}', '\u{a9e4}'), + ('\u{a9e6}', '\u{a9e6}'), ('\u{a9e7}', '\u{a9ef}'), ('\u{a9fa}', '\u{a9fe}'), ('\u{aa00}', + '\u{aa28}'), ('\u{aa40}', '\u{aa42}'), ('\u{aa44}', '\u{aa4b}'), ('\u{aa60}', '\u{aa6f}'), + ('\u{aa70}', '\u{aa70}'), ('\u{aa71}', '\u{aa76}'), ('\u{aa7a}', '\u{aa7a}'), ('\u{aa7e}', + '\u{aaaf}'), ('\u{aab1}', '\u{aab1}'), ('\u{aab5}', '\u{aab6}'), ('\u{aab9}', '\u{aabd}'), + ('\u{aac0}', '\u{aac0}'), ('\u{aac2}', '\u{aac2}'), ('\u{aadb}', '\u{aadc}'), ('\u{aadd}', + '\u{aadd}'), ('\u{aae0}', '\u{aaea}'), ('\u{aaf2}', '\u{aaf2}'), ('\u{aaf3}', '\u{aaf4}'), + ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', + '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab5f}'), + ('\u{ab64}', '\u{ab65}'), ('\u{abc0}', '\u{abe2}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', + '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), + ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb1d}'), ('\u{fb1f}', + '\u{fb28}'), ('\u{fb2a}', '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), + ('\u{fb40}', '\u{fb41}'), ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', + '\u{fc5d}'), ('\u{fc64}', '\u{fd3d}'), ('\u{fd50}', '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), + ('\u{fdf0}', '\u{fdf9}'), ('\u{fe71}', '\u{fe71}'), ('\u{fe73}', '\u{fe73}'), ('\u{fe77}', + '\u{fe77}'), ('\u{fe79}', '\u{fe79}'), ('\u{fe7b}', '\u{fe7b}'), ('\u{fe7d}', '\u{fe7d}'), + ('\u{fe7f}', '\u{fefc}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', + '\u{ff6f}'), ('\u{ff70}', '\u{ff70}'), ('\u{ff71}', '\u{ff9d}'), ('\u{ffa0}', '\u{ffbe}'), + ('\u{ffc2}', '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', + '\u{ffdc}'), ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', + '\u{1003a}'), ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', + '\u{1005d}'), ('\u{10080}', '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{10280}', + '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{10300}', '\u{1031f}'), ('\u{10330}', + '\u{10340}'), ('\u{10341}', '\u{10341}'), ('\u{10342}', '\u{10349}'), ('\u{1034a}', + '\u{1034a}'), ('\u{10350}', '\u{10375}'), ('\u{10380}', '\u{1039d}'), ('\u{103a0}', + '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), ('\u{103d1}', '\u{103d5}'), ('\u{10400}', + '\u{1044f}'), ('\u{10450}', '\u{1049d}'), ('\u{10500}', '\u{10527}'), ('\u{10530}', + '\u{10563}'), ('\u{10600}', '\u{10736}'), ('\u{10740}', '\u{10755}'), ('\u{10760}', + '\u{10767}'), ('\u{10800}', '\u{10805}'), ('\u{10808}', '\u{10808}'), ('\u{1080a}', + '\u{10835}'), ('\u{10837}', '\u{10838}'), ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', + '\u{10855}'), ('\u{10860}', '\u{10876}'), ('\u{10880}', '\u{1089e}'), ('\u{10900}', + '\u{10915}'), ('\u{10920}', '\u{10939}'), ('\u{10980}', '\u{109b7}'), ('\u{109be}', + '\u{109bf}'), ('\u{10a00}', '\u{10a00}'), ('\u{10a10}', '\u{10a13}'), ('\u{10a15}', + '\u{10a17}'), ('\u{10a19}', '\u{10a33}'), ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', + '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), ('\u{10ac9}', '\u{10ae4}'), ('\u{10b00}', + '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', + '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), ('\u{11003}', '\u{11037}'), ('\u{11083}', + '\u{110af}'), ('\u{110d0}', '\u{110e8}'), ('\u{11103}', '\u{11126}'), ('\u{11150}', + '\u{11172}'), ('\u{11176}', '\u{11176}'), ('\u{11183}', '\u{111b2}'), ('\u{111c1}', + '\u{111c4}'), ('\u{111da}', '\u{111da}'), ('\u{11200}', '\u{11211}'), ('\u{11213}', + '\u{1122b}'), ('\u{112b0}', '\u{112de}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', + '\u{11310}'), ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', + '\u{11333}'), ('\u{11335}', '\u{11339}'), ('\u{1133d}', '\u{1133d}'), ('\u{1135d}', + '\u{11361}'), ('\u{11480}', '\u{114af}'), ('\u{114c4}', '\u{114c5}'), ('\u{114c7}', + '\u{114c7}'), ('\u{11580}', '\u{115ae}'), ('\u{11600}', '\u{1162f}'), ('\u{11644}', + '\u{11644}'), ('\u{11680}', '\u{116aa}'), ('\u{118a0}', '\u{118df}'), ('\u{118ff}', + '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), ('\u{12000}', '\u{12398}'), ('\u{12400}', + '\u{1246e}'), ('\u{13000}', '\u{1342e}'), ('\u{16800}', '\u{16a38}'), ('\u{16a40}', + '\u{16a5e}'), ('\u{16ad0}', '\u{16aed}'), ('\u{16b00}', '\u{16b2f}'), ('\u{16b40}', + '\u{16b43}'), ('\u{16b63}', '\u{16b77}'), ('\u{16b7d}', '\u{16b8f}'), ('\u{16f00}', + '\u{16f44}'), ('\u{16f50}', '\u{16f50}'), ('\u{16f93}', '\u{16f9f}'), ('\u{1b000}', + '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', + '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', + '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', + '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', + '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', + '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', + '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', + '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', + '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', + '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', + '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', + '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1e800}', '\u{1e8c4}'), ('\u{1ee00}', + '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', + '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', + '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', + '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', + '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', + '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', + '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', + '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', + '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', + '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', + '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), ('\u{1eeab}', '\u{1eebb}'), ('\u{20000}', + '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', + '\u{2fa1d}') ]; - pub const Yi_table: &'static [(char, char)] = &[ - ('\u{a000}', '\u{a014}'), ('\u{a015}', '\u{a015}'), ('\u{a016}', '\u{a48c}'), ('\u{a490}', - '\u{a4c6}') - ]; + pub fn XID_Start(c: char) -> bool { + super::bsearch_range_table(c, XID_Start_table) + } } pub mod property { - pub const Join_Control_table: &'static [(char, char)] = &[ - ('\u{200c}', '\u{200d}') - ]; - - pub const Noncharacter_Code_Point_table: &'static [(char, char)] = &[ - ('\u{fdd0}', '\u{fdef}'), ('\u{fffe}', '\u{ffff}'), ('\u{1fffe}', '\u{1ffff}'), - ('\u{2fffe}', '\u{2ffff}'), ('\u{3fffe}', '\u{3ffff}'), ('\u{4fffe}', '\u{4ffff}'), - ('\u{5fffe}', '\u{5ffff}'), ('\u{6fffe}', '\u{6ffff}'), ('\u{7fffe}', '\u{7ffff}'), - ('\u{8fffe}', '\u{8ffff}'), ('\u{9fffe}', '\u{9ffff}'), ('\u{afffe}', '\u{affff}'), - ('\u{bfffe}', '\u{bffff}'), ('\u{cfffe}', '\u{cffff}'), ('\u{dfffe}', '\u{dffff}'), - ('\u{efffe}', '\u{effff}'), ('\u{ffffe}', '\u{fffff}') - ]; - pub const White_Space_table: &'static [(char, char)] = &[ ('\u{9}', '\u{d}'), ('\u{20}', '\u{20}'), ('\u{85}', '\u{85}'), ('\u{a0}', '\u{a0}'), ('\u{1680}', '\u{1680}'), ('\u{2000}', '\u{200a}'), ('\u{2028}', '\u{2028}'), ('\u{2029}', @@ -3944,304 +1253,6 @@ pub mod property { } -pub mod regex { - pub const UNICODE_CLASSES: &'static [(&'static str, &'static [(char, char)])] = &[ - ("Alphabetic", super::derived_property::Alphabetic_table), ("Arabic", - super::script::Arabic_table), ("Armenian", super::script::Armenian_table), ("Avestan", - super::script::Avestan_table), ("Balinese", super::script::Balinese_table), ("Bamum", - super::script::Bamum_table), ("Bassa_Vah", super::script::Bassa_Vah_table), ("Batak", - super::script::Batak_table), ("Bengali", super::script::Bengali_table), ("Bopomofo", - super::script::Bopomofo_table), ("Brahmi", super::script::Brahmi_table), ("Braille", - super::script::Braille_table), ("Buginese", super::script::Buginese_table), ("Buhid", - super::script::Buhid_table), ("C", super::general_category::C_table), - ("Canadian_Aboriginal", super::script::Canadian_Aboriginal_table), ("Carian", - super::script::Carian_table), ("Caucasian_Albanian", - super::script::Caucasian_Albanian_table), ("Cc", super::general_category::Cc_table), ("Cf", - super::general_category::Cf_table), ("Chakma", super::script::Chakma_table), ("Cham", - super::script::Cham_table), ("Cherokee", super::script::Cherokee_table), ("Cn", - super::general_category::Cn_table), ("Co", super::general_category::Co_table), ("Common", - super::script::Common_table), ("Coptic", super::script::Coptic_table), ("Cuneiform", - super::script::Cuneiform_table), ("Cypriot", super::script::Cypriot_table), ("Cyrillic", - super::script::Cyrillic_table), ("Default_Ignorable_Code_Point", - super::derived_property::Default_Ignorable_Code_Point_table), ("Deseret", - super::script::Deseret_table), ("Devanagari", super::script::Devanagari_table), ("Duployan", - super::script::Duployan_table), ("Egyptian_Hieroglyphs", - super::script::Egyptian_Hieroglyphs_table), ("Elbasan", super::script::Elbasan_table), - ("Ethiopic", super::script::Ethiopic_table), ("Georgian", super::script::Georgian_table), - ("Glagolitic", super::script::Glagolitic_table), ("Gothic", super::script::Gothic_table), - ("Grantha", super::script::Grantha_table), ("Greek", super::script::Greek_table), - ("Gujarati", super::script::Gujarati_table), ("Gurmukhi", super::script::Gurmukhi_table), - ("Han", super::script::Han_table), ("Hangul", super::script::Hangul_table), ("Hanunoo", - super::script::Hanunoo_table), ("Hebrew", super::script::Hebrew_table), ("Hiragana", - super::script::Hiragana_table), ("Imperial_Aramaic", super::script::Imperial_Aramaic_table), - ("Inherited", super::script::Inherited_table), ("Inscriptional_Pahlavi", - super::script::Inscriptional_Pahlavi_table), ("Inscriptional_Parthian", - super::script::Inscriptional_Parthian_table), ("Javanese", super::script::Javanese_table), - ("Join_Control", super::property::Join_Control_table), ("Kaithi", - super::script::Kaithi_table), ("Kannada", super::script::Kannada_table), ("Katakana", - super::script::Katakana_table), ("Kayah_Li", super::script::Kayah_Li_table), ("Kharoshthi", - super::script::Kharoshthi_table), ("Khmer", super::script::Khmer_table), ("Khojki", - super::script::Khojki_table), ("Khudawadi", super::script::Khudawadi_table), ("L", - super::general_category::L_table), ("LC", super::general_category::LC_table), ("Lao", - super::script::Lao_table), ("Latin", super::script::Latin_table), ("Lepcha", - super::script::Lepcha_table), ("Limbu", super::script::Limbu_table), ("Linear_A", - super::script::Linear_A_table), ("Linear_B", super::script::Linear_B_table), ("Lisu", - super::script::Lisu_table), ("Ll", super::general_category::Ll_table), ("Lm", - super::general_category::Lm_table), ("Lo", super::general_category::Lo_table), ("Lowercase", - super::derived_property::Lowercase_table), ("Lt", super::general_category::Lt_table), ("Lu", - super::general_category::Lu_table), ("Lycian", super::script::Lycian_table), ("Lydian", - super::script::Lydian_table), ("M", super::general_category::M_table), ("Mahajani", - super::script::Mahajani_table), ("Malayalam", super::script::Malayalam_table), ("Mandaic", - super::script::Mandaic_table), ("Manichaean", super::script::Manichaean_table), ("Mc", - super::general_category::Mc_table), ("Me", super::general_category::Me_table), - ("Meetei_Mayek", super::script::Meetei_Mayek_table), ("Mende_Kikakui", - super::script::Mende_Kikakui_table), ("Meroitic_Cursive", - super::script::Meroitic_Cursive_table), ("Meroitic_Hieroglyphs", - super::script::Meroitic_Hieroglyphs_table), ("Miao", super::script::Miao_table), ("Mn", - super::general_category::Mn_table), ("Modi", super::script::Modi_table), ("Mongolian", - super::script::Mongolian_table), ("Mro", super::script::Mro_table), ("Myanmar", - super::script::Myanmar_table), ("N", super::general_category::N_table), ("Nabataean", - super::script::Nabataean_table), ("Nd", super::general_category::Nd_table), ("New_Tai_Lue", - super::script::New_Tai_Lue_table), ("Nko", super::script::Nko_table), ("Nl", - super::general_category::Nl_table), ("No", super::general_category::No_table), - ("Noncharacter_Code_Point", super::property::Noncharacter_Code_Point_table), ("Ogham", - super::script::Ogham_table), ("Ol_Chiki", super::script::Ol_Chiki_table), ("Old_Italic", - super::script::Old_Italic_table), ("Old_North_Arabian", - super::script::Old_North_Arabian_table), ("Old_Permic", super::script::Old_Permic_table), - ("Old_Persian", super::script::Old_Persian_table), ("Old_South_Arabian", - super::script::Old_South_Arabian_table), ("Old_Turkic", super::script::Old_Turkic_table), - ("Oriya", super::script::Oriya_table), ("Osmanya", super::script::Osmanya_table), ("P", - super::general_category::P_table), ("Pahawh_Hmong", super::script::Pahawh_Hmong_table), - ("Palmyrene", super::script::Palmyrene_table), ("Pau_Cin_Hau", - super::script::Pau_Cin_Hau_table), ("Pc", super::general_category::Pc_table), ("Pd", - super::general_category::Pd_table), ("Pe", super::general_category::Pe_table), ("Pf", - super::general_category::Pf_table), ("Phags_Pa", super::script::Phags_Pa_table), - ("Phoenician", super::script::Phoenician_table), ("Pi", super::general_category::Pi_table), - ("Po", super::general_category::Po_table), ("Ps", super::general_category::Ps_table), - ("Psalter_Pahlavi", super::script::Psalter_Pahlavi_table), ("Rejang", - super::script::Rejang_table), ("Runic", super::script::Runic_table), ("S", - super::general_category::S_table), ("Samaritan", super::script::Samaritan_table), - ("Saurashtra", super::script::Saurashtra_table), ("Sc", super::general_category::Sc_table), - ("Sharada", super::script::Sharada_table), ("Shavian", super::script::Shavian_table), - ("Siddham", super::script::Siddham_table), ("Sinhala", super::script::Sinhala_table), ("Sk", - super::general_category::Sk_table), ("Sm", super::general_category::Sm_table), ("So", - super::general_category::So_table), ("Sora_Sompeng", super::script::Sora_Sompeng_table), - ("Sundanese", super::script::Sundanese_table), ("Syloti_Nagri", - super::script::Syloti_Nagri_table), ("Syriac", super::script::Syriac_table), ("Tagalog", - super::script::Tagalog_table), ("Tagbanwa", super::script::Tagbanwa_table), ("Tai_Le", - super::script::Tai_Le_table), ("Tai_Tham", super::script::Tai_Tham_table), ("Tai_Viet", - super::script::Tai_Viet_table), ("Takri", super::script::Takri_table), ("Tamil", - super::script::Tamil_table), ("Telugu", super::script::Telugu_table), ("Thaana", - super::script::Thaana_table), ("Thai", super::script::Thai_table), ("Tibetan", - super::script::Tibetan_table), ("Tifinagh", super::script::Tifinagh_table), ("Tirhuta", - super::script::Tirhuta_table), ("Ugaritic", super::script::Ugaritic_table), ("Uppercase", - super::derived_property::Uppercase_table), ("Vai", super::script::Vai_table), - ("Warang_Citi", super::script::Warang_Citi_table), ("White_Space", - super::property::White_Space_table), ("XID_Continue", - super::derived_property::XID_Continue_table), ("XID_Start", - super::derived_property::XID_Start_table), ("Yi", super::script::Yi_table), ("Z", - super::general_category::Z_table), ("Zl", super::general_category::Zl_table), ("Zp", - super::general_category::Zp_table), ("Zs", super::general_category::Zs_table) - ]; - - pub const PERLD: &'static [(char, char)] = super::general_category::Nd_table; - - pub const PERLS: &'static [(char, char)] = super::property::White_Space_table; - - pub const PERLW: &'static [(char, char)] = &[ - ('\u{30}', '\u{39}'), ('\u{41}', '\u{5a}'), ('\u{5f}', '\u{5f}'), ('\u{61}', '\u{7a}'), - ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), - ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{2c1}'), ('\u{2c6}', '\u{2d1}'), ('\u{2e0}', '\u{2e4}'), - ('\u{2ec}', '\u{2ec}'), ('\u{2ee}', '\u{2ee}'), ('\u{300}', '\u{374}'), ('\u{376}', - '\u{377}'), ('\u{37a}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}', '\u{386}'), - ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'), ('\u{3a3}', - '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{483}', '\u{52f}'), ('\u{531}', '\u{556}'), - ('\u{559}', '\u{559}'), ('\u{561}', '\u{587}'), ('\u{591}', '\u{5bd}'), ('\u{5bf}', - '\u{5bf}'), ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), - ('\u{5d0}', '\u{5ea}'), ('\u{5f0}', '\u{5f2}'), ('\u{610}', '\u{61a}'), ('\u{620}', - '\u{669}'), ('\u{66e}', '\u{6d3}'), ('\u{6d5}', '\u{6dc}'), ('\u{6df}', '\u{6e8}'), - ('\u{6ea}', '\u{6fc}'), ('\u{6ff}', '\u{6ff}'), ('\u{710}', '\u{74a}'), ('\u{74d}', - '\u{7b1}'), ('\u{7c0}', '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{800}', '\u{82d}'), - ('\u{840}', '\u{85b}'), ('\u{8a0}', '\u{8b2}'), ('\u{8e4}', '\u{963}'), ('\u{966}', - '\u{96f}'), ('\u{971}', '\u{983}'), ('\u{985}', '\u{98c}'), ('\u{98f}', '\u{990}'), - ('\u{993}', '\u{9a8}'), ('\u{9aa}', '\u{9b0}'), ('\u{9b2}', '\u{9b2}'), ('\u{9b6}', - '\u{9b9}'), ('\u{9bc}', '\u{9c4}'), ('\u{9c7}', '\u{9c8}'), ('\u{9cb}', '\u{9ce}'), - ('\u{9d7}', '\u{9d7}'), ('\u{9dc}', '\u{9dd}'), ('\u{9df}', '\u{9e3}'), ('\u{9e6}', - '\u{9f1}'), ('\u{a01}', '\u{a03}'), ('\u{a05}', '\u{a0a}'), ('\u{a0f}', '\u{a10}'), - ('\u{a13}', '\u{a28}'), ('\u{a2a}', '\u{a30}'), ('\u{a32}', '\u{a33}'), ('\u{a35}', - '\u{a36}'), ('\u{a38}', '\u{a39}'), ('\u{a3c}', '\u{a3c}'), ('\u{a3e}', '\u{a42}'), - ('\u{a47}', '\u{a48}'), ('\u{a4b}', '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a59}', - '\u{a5c}'), ('\u{a5e}', '\u{a5e}'), ('\u{a66}', '\u{a75}'), ('\u{a81}', '\u{a83}'), - ('\u{a85}', '\u{a8d}'), ('\u{a8f}', '\u{a91}'), ('\u{a93}', '\u{aa8}'), ('\u{aaa}', - '\u{ab0}'), ('\u{ab2}', '\u{ab3}'), ('\u{ab5}', '\u{ab9}'), ('\u{abc}', '\u{ac5}'), - ('\u{ac7}', '\u{ac9}'), ('\u{acb}', '\u{acd}'), ('\u{ad0}', '\u{ad0}'), ('\u{ae0}', - '\u{ae3}'), ('\u{ae6}', '\u{aef}'), ('\u{b01}', '\u{b03}'), ('\u{b05}', '\u{b0c}'), - ('\u{b0f}', '\u{b10}'), ('\u{b13}', '\u{b28}'), ('\u{b2a}', '\u{b30}'), ('\u{b32}', - '\u{b33}'), ('\u{b35}', '\u{b39}'), ('\u{b3c}', '\u{b44}'), ('\u{b47}', '\u{b48}'), - ('\u{b4b}', '\u{b4d}'), ('\u{b56}', '\u{b57}'), ('\u{b5c}', '\u{b5d}'), ('\u{b5f}', - '\u{b63}'), ('\u{b66}', '\u{b6f}'), ('\u{b71}', '\u{b71}'), ('\u{b82}', '\u{b83}'), - ('\u{b85}', '\u{b8a}'), ('\u{b8e}', '\u{b90}'), ('\u{b92}', '\u{b95}'), ('\u{b99}', - '\u{b9a}'), ('\u{b9c}', '\u{b9c}'), ('\u{b9e}', '\u{b9f}'), ('\u{ba3}', '\u{ba4}'), - ('\u{ba8}', '\u{baa}'), ('\u{bae}', '\u{bb9}'), ('\u{bbe}', '\u{bc2}'), ('\u{bc6}', - '\u{bc8}'), ('\u{bca}', '\u{bcd}'), ('\u{bd0}', '\u{bd0}'), ('\u{bd7}', '\u{bd7}'), - ('\u{be6}', '\u{bef}'), ('\u{c00}', '\u{c03}'), ('\u{c05}', '\u{c0c}'), ('\u{c0e}', - '\u{c10}'), ('\u{c12}', '\u{c28}'), ('\u{c2a}', '\u{c39}'), ('\u{c3d}', '\u{c44}'), - ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'), ('\u{c58}', - '\u{c59}'), ('\u{c60}', '\u{c63}'), ('\u{c66}', '\u{c6f}'), ('\u{c81}', '\u{c83}'), - ('\u{c85}', '\u{c8c}'), ('\u{c8e}', '\u{c90}'), ('\u{c92}', '\u{ca8}'), ('\u{caa}', - '\u{cb3}'), ('\u{cb5}', '\u{cb9}'), ('\u{cbc}', '\u{cc4}'), ('\u{cc6}', '\u{cc8}'), - ('\u{cca}', '\u{ccd}'), ('\u{cd5}', '\u{cd6}'), ('\u{cde}', '\u{cde}'), ('\u{ce0}', - '\u{ce3}'), ('\u{ce6}', '\u{cef}'), ('\u{cf1}', '\u{cf2}'), ('\u{d01}', '\u{d03}'), - ('\u{d05}', '\u{d0c}'), ('\u{d0e}', '\u{d10}'), ('\u{d12}', '\u{d3a}'), ('\u{d3d}', - '\u{d44}'), ('\u{d46}', '\u{d48}'), ('\u{d4a}', '\u{d4e}'), ('\u{d57}', '\u{d57}'), - ('\u{d60}', '\u{d63}'), ('\u{d66}', '\u{d6f}'), ('\u{d7a}', '\u{d7f}'), ('\u{d82}', - '\u{d83}'), ('\u{d85}', '\u{d96}'), ('\u{d9a}', '\u{db1}'), ('\u{db3}', '\u{dbb}'), - ('\u{dbd}', '\u{dbd}'), ('\u{dc0}', '\u{dc6}'), ('\u{dca}', '\u{dca}'), ('\u{dcf}', - '\u{dd4}'), ('\u{dd6}', '\u{dd6}'), ('\u{dd8}', '\u{ddf}'), ('\u{de6}', '\u{def}'), - ('\u{df2}', '\u{df3}'), ('\u{e01}', '\u{e3a}'), ('\u{e40}', '\u{e4e}'), ('\u{e50}', - '\u{e59}'), ('\u{e81}', '\u{e82}'), ('\u{e84}', '\u{e84}'), ('\u{e87}', '\u{e88}'), - ('\u{e8a}', '\u{e8a}'), ('\u{e8d}', '\u{e8d}'), ('\u{e94}', '\u{e97}'), ('\u{e99}', - '\u{e9f}'), ('\u{ea1}', '\u{ea3}'), ('\u{ea5}', '\u{ea5}'), ('\u{ea7}', '\u{ea7}'), - ('\u{eaa}', '\u{eab}'), ('\u{ead}', '\u{eb9}'), ('\u{ebb}', '\u{ebd}'), ('\u{ec0}', - '\u{ec4}'), ('\u{ec6}', '\u{ec6}'), ('\u{ec8}', '\u{ecd}'), ('\u{ed0}', '\u{ed9}'), - ('\u{edc}', '\u{edf}'), ('\u{f00}', '\u{f00}'), ('\u{f18}', '\u{f19}'), ('\u{f20}', - '\u{f29}'), ('\u{f35}', '\u{f35}'), ('\u{f37}', '\u{f37}'), ('\u{f39}', '\u{f39}'), - ('\u{f3e}', '\u{f47}'), ('\u{f49}', '\u{f6c}'), ('\u{f71}', '\u{f84}'), ('\u{f86}', - '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}', '\u{fc6}'), ('\u{1000}', '\u{1049}'), - ('\u{1050}', '\u{109d}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'), ('\u{10cd}', - '\u{10cd}'), ('\u{10d0}', '\u{10fa}'), ('\u{10fc}', '\u{1248}'), ('\u{124a}', '\u{124d}'), - ('\u{1250}', '\u{1256}'), ('\u{1258}', '\u{1258}'), ('\u{125a}', '\u{125d}'), ('\u{1260}', - '\u{1288}'), ('\u{128a}', '\u{128d}'), ('\u{1290}', '\u{12b0}'), ('\u{12b2}', '\u{12b5}'), - ('\u{12b8}', '\u{12be}'), ('\u{12c0}', '\u{12c0}'), ('\u{12c2}', '\u{12c5}'), ('\u{12c8}', - '\u{12d6}'), ('\u{12d8}', '\u{1310}'), ('\u{1312}', '\u{1315}'), ('\u{1318}', '\u{135a}'), - ('\u{135d}', '\u{135f}'), ('\u{1380}', '\u{138f}'), ('\u{13a0}', '\u{13f4}'), ('\u{1401}', - '\u{166c}'), ('\u{166f}', '\u{167f}'), ('\u{1681}', '\u{169a}'), ('\u{16a0}', '\u{16ea}'), - ('\u{16ee}', '\u{16f8}'), ('\u{1700}', '\u{170c}'), ('\u{170e}', '\u{1714}'), ('\u{1720}', - '\u{1734}'), ('\u{1740}', '\u{1753}'), ('\u{1760}', '\u{176c}'), ('\u{176e}', '\u{1770}'), - ('\u{1772}', '\u{1773}'), ('\u{1780}', '\u{17d3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dc}', - '\u{17dd}'), ('\u{17e0}', '\u{17e9}'), ('\u{180b}', '\u{180d}'), ('\u{1810}', '\u{1819}'), - ('\u{1820}', '\u{1877}'), ('\u{1880}', '\u{18aa}'), ('\u{18b0}', '\u{18f5}'), ('\u{1900}', - '\u{191e}'), ('\u{1920}', '\u{192b}'), ('\u{1930}', '\u{193b}'), ('\u{1946}', '\u{196d}'), - ('\u{1970}', '\u{1974}'), ('\u{1980}', '\u{19ab}'), ('\u{19b0}', '\u{19c9}'), ('\u{19d0}', - '\u{19d9}'), ('\u{1a00}', '\u{1a1b}'), ('\u{1a20}', '\u{1a5e}'), ('\u{1a60}', '\u{1a7c}'), - ('\u{1a7f}', '\u{1a89}'), ('\u{1a90}', '\u{1a99}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1ab0}', - '\u{1abe}'), ('\u{1b00}', '\u{1b4b}'), ('\u{1b50}', '\u{1b59}'), ('\u{1b6b}', '\u{1b73}'), - ('\u{1b80}', '\u{1bf3}'), ('\u{1c00}', '\u{1c37}'), ('\u{1c40}', '\u{1c49}'), ('\u{1c4d}', - '\u{1c7d}'), ('\u{1cd0}', '\u{1cd2}'), ('\u{1cd4}', '\u{1cf6}'), ('\u{1cf8}', '\u{1cf9}'), - ('\u{1d00}', '\u{1df5}'), ('\u{1dfc}', '\u{1f15}'), ('\u{1f18}', '\u{1f1d}'), ('\u{1f20}', - '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'), ('\u{1f59}', '\u{1f59}'), - ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}', '\u{1f7d}'), ('\u{1f80}', - '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'), ('\u{1fc2}', '\u{1fc4}'), - ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}', '\u{1fdb}'), ('\u{1fe0}', - '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'), ('\u{200c}', '\u{200d}'), - ('\u{203f}', '\u{2040}'), ('\u{2054}', '\u{2054}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', - '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{20d0}', '\u{20f0}'), ('\u{2102}', '\u{2102}'), - ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'), ('\u{2119}', - '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}', '\u{2128}'), - ('\u{212a}', '\u{212d}'), ('\u{212f}', '\u{2139}'), ('\u{213c}', '\u{213f}'), ('\u{2145}', - '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}', '\u{2188}'), ('\u{24b6}', '\u{24e9}'), - ('\u{2c00}', '\u{2c2e}'), ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', - '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'), - ('\u{2d30}', '\u{2d67}'), ('\u{2d6f}', '\u{2d6f}'), ('\u{2d7f}', '\u{2d96}'), ('\u{2da0}', - '\u{2da6}'), ('\u{2da8}', '\u{2dae}'), ('\u{2db0}', '\u{2db6}'), ('\u{2db8}', '\u{2dbe}'), - ('\u{2dc0}', '\u{2dc6}'), ('\u{2dc8}', '\u{2dce}'), ('\u{2dd0}', '\u{2dd6}'), ('\u{2dd8}', - '\u{2dde}'), ('\u{2de0}', '\u{2dff}'), ('\u{2e2f}', '\u{2e2f}'), ('\u{3005}', '\u{3007}'), - ('\u{3021}', '\u{302f}'), ('\u{3031}', '\u{3035}'), ('\u{3038}', '\u{303c}'), ('\u{3041}', - '\u{3096}'), ('\u{3099}', '\u{309a}'), ('\u{309d}', '\u{309f}'), ('\u{30a1}', '\u{30fa}'), - ('\u{30fc}', '\u{30ff}'), ('\u{3105}', '\u{312d}'), ('\u{3131}', '\u{318e}'), ('\u{31a0}', - '\u{31ba}'), ('\u{31f0}', '\u{31ff}'), ('\u{3400}', '\u{4db5}'), ('\u{4e00}', '\u{9fcc}'), - ('\u{a000}', '\u{a48c}'), ('\u{a4d0}', '\u{a4fd}'), ('\u{a500}', '\u{a60c}'), ('\u{a610}', - '\u{a62b}'), ('\u{a640}', '\u{a672}'), ('\u{a674}', '\u{a67d}'), ('\u{a67f}', '\u{a69d}'), - ('\u{a69f}', '\u{a6f1}'), ('\u{a717}', '\u{a71f}'), ('\u{a722}', '\u{a788}'), ('\u{a78b}', - '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b1}'), ('\u{a7f7}', '\u{a827}'), - ('\u{a840}', '\u{a873}'), ('\u{a880}', '\u{a8c4}'), ('\u{a8d0}', '\u{a8d9}'), ('\u{a8e0}', - '\u{a8f7}'), ('\u{a8fb}', '\u{a8fb}'), ('\u{a900}', '\u{a92d}'), ('\u{a930}', '\u{a953}'), - ('\u{a960}', '\u{a97c}'), ('\u{a980}', '\u{a9c0}'), ('\u{a9cf}', '\u{a9d9}'), ('\u{a9e0}', - '\u{a9fe}'), ('\u{aa00}', '\u{aa36}'), ('\u{aa40}', '\u{aa4d}'), ('\u{aa50}', '\u{aa59}'), - ('\u{aa60}', '\u{aa76}'), ('\u{aa7a}', '\u{aac2}'), ('\u{aadb}', '\u{aadd}'), ('\u{aae0}', - '\u{aaef}'), ('\u{aaf2}', '\u{aaf6}'), ('\u{ab01}', '\u{ab06}'), ('\u{ab09}', '\u{ab0e}'), - ('\u{ab11}', '\u{ab16}'), ('\u{ab20}', '\u{ab26}'), ('\u{ab28}', '\u{ab2e}'), ('\u{ab30}', - '\u{ab5a}'), ('\u{ab5c}', '\u{ab5f}'), ('\u{ab64}', '\u{ab65}'), ('\u{abc0}', '\u{abea}'), - ('\u{abec}', '\u{abed}'), ('\u{abf0}', '\u{abf9}'), ('\u{ac00}', '\u{d7a3}'), ('\u{d7b0}', - '\u{d7c6}'), ('\u{d7cb}', '\u{d7fb}'), ('\u{f900}', '\u{fa6d}'), ('\u{fa70}', '\u{fad9}'), - ('\u{fb00}', '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{fb1d}', '\u{fb28}'), ('\u{fb2a}', - '\u{fb36}'), ('\u{fb38}', '\u{fb3c}'), ('\u{fb3e}', '\u{fb3e}'), ('\u{fb40}', '\u{fb41}'), - ('\u{fb43}', '\u{fb44}'), ('\u{fb46}', '\u{fbb1}'), ('\u{fbd3}', '\u{fd3d}'), ('\u{fd50}', - '\u{fd8f}'), ('\u{fd92}', '\u{fdc7}'), ('\u{fdf0}', '\u{fdfb}'), ('\u{fe00}', '\u{fe0f}'), - ('\u{fe20}', '\u{fe2d}'), ('\u{fe33}', '\u{fe34}'), ('\u{fe4d}', '\u{fe4f}'), ('\u{fe70}', - '\u{fe74}'), ('\u{fe76}', '\u{fefc}'), ('\u{ff10}', '\u{ff19}'), ('\u{ff21}', '\u{ff3a}'), - ('\u{ff3f}', '\u{ff3f}'), ('\u{ff41}', '\u{ff5a}'), ('\u{ff66}', '\u{ffbe}'), ('\u{ffc2}', - '\u{ffc7}'), ('\u{ffca}', '\u{ffcf}'), ('\u{ffd2}', '\u{ffd7}'), ('\u{ffda}', '\u{ffdc}'), - ('\u{10000}', '\u{1000b}'), ('\u{1000d}', '\u{10026}'), ('\u{10028}', '\u{1003a}'), - ('\u{1003c}', '\u{1003d}'), ('\u{1003f}', '\u{1004d}'), ('\u{10050}', '\u{1005d}'), - ('\u{10080}', '\u{100fa}'), ('\u{10140}', '\u{10174}'), ('\u{101fd}', '\u{101fd}'), - ('\u{10280}', '\u{1029c}'), ('\u{102a0}', '\u{102d0}'), ('\u{102e0}', '\u{102e0}'), - ('\u{10300}', '\u{1031f}'), ('\u{10330}', '\u{1034a}'), ('\u{10350}', '\u{1037a}'), - ('\u{10380}', '\u{1039d}'), ('\u{103a0}', '\u{103c3}'), ('\u{103c8}', '\u{103cf}'), - ('\u{103d1}', '\u{103d5}'), ('\u{10400}', '\u{1049d}'), ('\u{104a0}', '\u{104a9}'), - ('\u{10500}', '\u{10527}'), ('\u{10530}', '\u{10563}'), ('\u{10600}', '\u{10736}'), - ('\u{10740}', '\u{10755}'), ('\u{10760}', '\u{10767}'), ('\u{10800}', '\u{10805}'), - ('\u{10808}', '\u{10808}'), ('\u{1080a}', '\u{10835}'), ('\u{10837}', '\u{10838}'), - ('\u{1083c}', '\u{1083c}'), ('\u{1083f}', '\u{10855}'), ('\u{10860}', '\u{10876}'), - ('\u{10880}', '\u{1089e}'), ('\u{10900}', '\u{10915}'), ('\u{10920}', '\u{10939}'), - ('\u{10980}', '\u{109b7}'), ('\u{109be}', '\u{109bf}'), ('\u{10a00}', '\u{10a03}'), - ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}', '\u{10a13}'), ('\u{10a15}', '\u{10a17}'), - ('\u{10a19}', '\u{10a33}'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), - ('\u{10a60}', '\u{10a7c}'), ('\u{10a80}', '\u{10a9c}'), ('\u{10ac0}', '\u{10ac7}'), - ('\u{10ac9}', '\u{10ae6}'), ('\u{10b00}', '\u{10b35}'), ('\u{10b40}', '\u{10b55}'), - ('\u{10b60}', '\u{10b72}'), ('\u{10b80}', '\u{10b91}'), ('\u{10c00}', '\u{10c48}'), - ('\u{11000}', '\u{11046}'), ('\u{11066}', '\u{1106f}'), ('\u{1107f}', '\u{110ba}'), - ('\u{110d0}', '\u{110e8}'), ('\u{110f0}', '\u{110f9}'), ('\u{11100}', '\u{11134}'), - ('\u{11136}', '\u{1113f}'), ('\u{11150}', '\u{11173}'), ('\u{11176}', '\u{11176}'), - ('\u{11180}', '\u{111c4}'), ('\u{111d0}', '\u{111da}'), ('\u{11200}', '\u{11211}'), - ('\u{11213}', '\u{11237}'), ('\u{112b0}', '\u{112ea}'), ('\u{112f0}', '\u{112f9}'), - ('\u{11301}', '\u{11303}'), ('\u{11305}', '\u{1130c}'), ('\u{1130f}', '\u{11310}'), - ('\u{11313}', '\u{11328}'), ('\u{1132a}', '\u{11330}'), ('\u{11332}', '\u{11333}'), - ('\u{11335}', '\u{11339}'), ('\u{1133c}', '\u{11344}'), ('\u{11347}', '\u{11348}'), - ('\u{1134b}', '\u{1134d}'), ('\u{11357}', '\u{11357}'), ('\u{1135d}', '\u{11363}'), - ('\u{11366}', '\u{1136c}'), ('\u{11370}', '\u{11374}'), ('\u{11480}', '\u{114c5}'), - ('\u{114c7}', '\u{114c7}'), ('\u{114d0}', '\u{114d9}'), ('\u{11580}', '\u{115b5}'), - ('\u{115b8}', '\u{115c0}'), ('\u{11600}', '\u{11640}'), ('\u{11644}', '\u{11644}'), - ('\u{11650}', '\u{11659}'), ('\u{11680}', '\u{116b7}'), ('\u{116c0}', '\u{116c9}'), - ('\u{118a0}', '\u{118e9}'), ('\u{118ff}', '\u{118ff}'), ('\u{11ac0}', '\u{11af8}'), - ('\u{12000}', '\u{12398}'), ('\u{12400}', '\u{1246e}'), ('\u{13000}', '\u{1342e}'), - ('\u{16800}', '\u{16a38}'), ('\u{16a40}', '\u{16a5e}'), ('\u{16a60}', '\u{16a69}'), - ('\u{16ad0}', '\u{16aed}'), ('\u{16af0}', '\u{16af4}'), ('\u{16b00}', '\u{16b36}'), - ('\u{16b40}', '\u{16b43}'), ('\u{16b50}', '\u{16b59}'), ('\u{16b63}', '\u{16b77}'), - ('\u{16b7d}', '\u{16b8f}'), ('\u{16f00}', '\u{16f44}'), ('\u{16f50}', '\u{16f7e}'), - ('\u{16f8f}', '\u{16f9f}'), ('\u{1b000}', '\u{1b001}'), ('\u{1bc00}', '\u{1bc6a}'), - ('\u{1bc70}', '\u{1bc7c}'), ('\u{1bc80}', '\u{1bc88}'), ('\u{1bc90}', '\u{1bc99}'), - ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1d165}', '\u{1d169}'), ('\u{1d16d}', '\u{1d172}'), - ('\u{1d17b}', '\u{1d182}'), ('\u{1d185}', '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), - ('\u{1d242}', '\u{1d244}'), ('\u{1d400}', '\u{1d454}'), ('\u{1d456}', '\u{1d49c}'), - ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'), ('\u{1d4a5}', '\u{1d4a6}'), - ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'), ('\u{1d4bb}', '\u{1d4bb}'), - ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'), ('\u{1d507}', '\u{1d50a}'), - ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'), ('\u{1d51e}', '\u{1d539}'), - ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'), ('\u{1d546}', '\u{1d546}'), - ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'), ('\u{1d6a8}', '\u{1d6c0}'), - ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'), ('\u{1d6fc}', '\u{1d714}'), - ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'), ('\u{1d750}', '\u{1d76e}'), - ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'), ('\u{1d7aa}', '\u{1d7c2}'), - ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1d7ce}', '\u{1d7ff}'), ('\u{1e800}', '\u{1e8c4}'), - ('\u{1e8d0}', '\u{1e8d6}'), ('\u{1ee00}', '\u{1ee03}'), ('\u{1ee05}', '\u{1ee1f}'), - ('\u{1ee21}', '\u{1ee22}'), ('\u{1ee24}', '\u{1ee24}'), ('\u{1ee27}', '\u{1ee27}'), - ('\u{1ee29}', '\u{1ee32}'), ('\u{1ee34}', '\u{1ee37}'), ('\u{1ee39}', '\u{1ee39}'), - ('\u{1ee3b}', '\u{1ee3b}'), ('\u{1ee42}', '\u{1ee42}'), ('\u{1ee47}', '\u{1ee47}'), - ('\u{1ee49}', '\u{1ee49}'), ('\u{1ee4b}', '\u{1ee4b}'), ('\u{1ee4d}', '\u{1ee4f}'), - ('\u{1ee51}', '\u{1ee52}'), ('\u{1ee54}', '\u{1ee54}'), ('\u{1ee57}', '\u{1ee57}'), - ('\u{1ee59}', '\u{1ee59}'), ('\u{1ee5b}', '\u{1ee5b}'), ('\u{1ee5d}', '\u{1ee5d}'), - ('\u{1ee5f}', '\u{1ee5f}'), ('\u{1ee61}', '\u{1ee62}'), ('\u{1ee64}', '\u{1ee64}'), - ('\u{1ee67}', '\u{1ee6a}'), ('\u{1ee6c}', '\u{1ee72}'), ('\u{1ee74}', '\u{1ee77}'), - ('\u{1ee79}', '\u{1ee7c}'), ('\u{1ee7e}', '\u{1ee7e}'), ('\u{1ee80}', '\u{1ee89}'), - ('\u{1ee8b}', '\u{1ee9b}'), ('\u{1eea1}', '\u{1eea3}'), ('\u{1eea5}', '\u{1eea9}'), - ('\u{1eeab}', '\u{1eebb}'), ('\u{1f130}', '\u{1f149}'), ('\u{1f150}', '\u{1f169}'), - ('\u{1f170}', '\u{1f189}'), ('\u{20000}', '\u{2a6d6}'), ('\u{2a700}', '\u{2b734}'), - ('\u{2b740}', '\u{2b81d}'), ('\u{2f800}', '\u{2fa1d}'), ('\u{e0100}', '\u{e01ef}') - ]; - -} - pub mod normalization { // Canonical decompositions pub const canonical_table: &'static [(char, &'static [char])] = &[ @@ -7798,15 +4809,15 @@ pub mod grapheme { #[allow(non_camel_case_types)] #[derive(Clone, Copy)] pub enum GraphemeCat { - GC_LV, - GC_LVT, - GC_T, + GC_Control, GC_Extend, + GC_LVT, GC_V, - GC_Control, - GC_SpacingMark, GC_L, - GC_RegionalIndicator, + GC_Regional_Indicator, + GC_LV, + GC_T, + GC_SpacingMark, GC_Any, } @@ -7895,387 +4906,382 @@ pub mod grapheme { GC_Extend), ('\u{f3e}', '\u{f3f}', GC_SpacingMark), ('\u{f71}', '\u{f7e}', GC_Extend), ('\u{f7f}', '\u{f7f}', GC_SpacingMark), ('\u{f80}', '\u{f84}', GC_Extend), ('\u{f86}', '\u{f87}', GC_Extend), ('\u{f8d}', '\u{f97}', GC_Extend), ('\u{f99}', '\u{fbc}', GC_Extend), - ('\u{fc6}', '\u{fc6}', GC_Extend), ('\u{102b}', '\u{102c}', GC_SpacingMark), ('\u{102d}', - '\u{1030}', GC_Extend), ('\u{1031}', '\u{1031}', GC_SpacingMark), ('\u{1032}', '\u{1037}', - GC_Extend), ('\u{1038}', '\u{1038}', GC_SpacingMark), ('\u{1039}', '\u{103a}', GC_Extend), - ('\u{103b}', '\u{103c}', GC_SpacingMark), ('\u{103d}', '\u{103e}', GC_Extend), ('\u{1056}', - '\u{1057}', GC_SpacingMark), ('\u{1058}', '\u{1059}', GC_Extend), ('\u{105e}', '\u{1060}', - GC_Extend), ('\u{1062}', '\u{1064}', GC_SpacingMark), ('\u{1067}', '\u{106d}', - GC_SpacingMark), ('\u{1071}', '\u{1074}', GC_Extend), ('\u{1082}', '\u{1082}', GC_Extend), - ('\u{1083}', '\u{1084}', GC_SpacingMark), ('\u{1085}', '\u{1086}', GC_Extend), ('\u{1087}', - '\u{108c}', GC_SpacingMark), ('\u{108d}', '\u{108d}', GC_Extend), ('\u{108f}', '\u{108f}', - GC_SpacingMark), ('\u{109a}', '\u{109c}', GC_SpacingMark), ('\u{109d}', '\u{109d}', - GC_Extend), ('\u{1100}', '\u{115f}', GC_L), ('\u{1160}', '\u{11a7}', GC_V), ('\u{11a8}', - '\u{11ff}', GC_T), ('\u{135d}', '\u{135f}', GC_Extend), ('\u{1712}', '\u{1714}', GC_Extend), - ('\u{1732}', '\u{1734}', GC_Extend), ('\u{1752}', '\u{1753}', GC_Extend), ('\u{1772}', - '\u{1773}', GC_Extend), ('\u{17b4}', '\u{17b5}', GC_Extend), ('\u{17b6}', '\u{17b6}', - GC_SpacingMark), ('\u{17b7}', '\u{17bd}', GC_Extend), ('\u{17be}', '\u{17c5}', - GC_SpacingMark), ('\u{17c6}', '\u{17c6}', GC_Extend), ('\u{17c7}', '\u{17c8}', - GC_SpacingMark), ('\u{17c9}', '\u{17d3}', GC_Extend), ('\u{17dd}', '\u{17dd}', GC_Extend), - ('\u{180b}', '\u{180d}', GC_Extend), ('\u{180e}', '\u{180e}', GC_Control), ('\u{18a9}', - '\u{18a9}', GC_Extend), ('\u{1920}', '\u{1922}', GC_Extend), ('\u{1923}', '\u{1926}', - GC_SpacingMark), ('\u{1927}', '\u{1928}', GC_Extend), ('\u{1929}', '\u{192b}', - GC_SpacingMark), ('\u{1930}', '\u{1931}', GC_SpacingMark), ('\u{1932}', '\u{1932}', - GC_Extend), ('\u{1933}', '\u{1938}', GC_SpacingMark), ('\u{1939}', '\u{193b}', GC_Extend), - ('\u{19b0}', '\u{19c0}', GC_SpacingMark), ('\u{19c8}', '\u{19c9}', GC_SpacingMark), - ('\u{1a17}', '\u{1a18}', GC_Extend), ('\u{1a19}', '\u{1a1a}', GC_SpacingMark), ('\u{1a1b}', - '\u{1a1b}', GC_Extend), ('\u{1a55}', '\u{1a55}', GC_SpacingMark), ('\u{1a56}', '\u{1a56}', - GC_Extend), ('\u{1a57}', '\u{1a57}', GC_SpacingMark), ('\u{1a58}', '\u{1a5e}', GC_Extend), - ('\u{1a60}', '\u{1a60}', GC_Extend), ('\u{1a61}', '\u{1a61}', GC_SpacingMark), ('\u{1a62}', - '\u{1a62}', GC_Extend), ('\u{1a63}', '\u{1a64}', GC_SpacingMark), ('\u{1a65}', '\u{1a6c}', - GC_Extend), ('\u{1a6d}', '\u{1a72}', GC_SpacingMark), ('\u{1a73}', '\u{1a7c}', GC_Extend), - ('\u{1a7f}', '\u{1a7f}', GC_Extend), ('\u{1ab0}', '\u{1abd}', GC_Extend), ('\u{1abe}', - '\u{1abe}', GC_Extend), ('\u{1b00}', '\u{1b03}', GC_Extend), ('\u{1b04}', '\u{1b04}', - GC_SpacingMark), ('\u{1b34}', '\u{1b34}', GC_Extend), ('\u{1b35}', '\u{1b35}', - GC_SpacingMark), ('\u{1b36}', '\u{1b3a}', GC_Extend), ('\u{1b3b}', '\u{1b3b}', - GC_SpacingMark), ('\u{1b3c}', '\u{1b3c}', GC_Extend), ('\u{1b3d}', '\u{1b41}', - GC_SpacingMark), ('\u{1b42}', '\u{1b42}', GC_Extend), ('\u{1b43}', '\u{1b44}', - GC_SpacingMark), ('\u{1b6b}', '\u{1b73}', GC_Extend), ('\u{1b80}', '\u{1b81}', GC_Extend), - ('\u{1b82}', '\u{1b82}', GC_SpacingMark), ('\u{1ba1}', '\u{1ba1}', GC_SpacingMark), - ('\u{1ba2}', '\u{1ba5}', GC_Extend), ('\u{1ba6}', '\u{1ba7}', GC_SpacingMark), ('\u{1ba8}', - '\u{1ba9}', GC_Extend), ('\u{1baa}', '\u{1baa}', GC_SpacingMark), ('\u{1bab}', '\u{1bad}', - GC_Extend), ('\u{1be6}', '\u{1be6}', GC_Extend), ('\u{1be7}', '\u{1be7}', GC_SpacingMark), - ('\u{1be8}', '\u{1be9}', GC_Extend), ('\u{1bea}', '\u{1bec}', GC_SpacingMark), ('\u{1bed}', - '\u{1bed}', GC_Extend), ('\u{1bee}', '\u{1bee}', GC_SpacingMark), ('\u{1bef}', '\u{1bf1}', - GC_Extend), ('\u{1bf2}', '\u{1bf3}', GC_SpacingMark), ('\u{1c24}', '\u{1c2b}', - GC_SpacingMark), ('\u{1c2c}', '\u{1c33}', GC_Extend), ('\u{1c34}', '\u{1c35}', - GC_SpacingMark), ('\u{1c36}', '\u{1c37}', GC_Extend), ('\u{1cd0}', '\u{1cd2}', GC_Extend), - ('\u{1cd4}', '\u{1ce0}', GC_Extend), ('\u{1ce1}', '\u{1ce1}', GC_SpacingMark), ('\u{1ce2}', - '\u{1ce8}', GC_Extend), ('\u{1ced}', '\u{1ced}', GC_Extend), ('\u{1cf2}', '\u{1cf3}', - GC_SpacingMark), ('\u{1cf4}', '\u{1cf4}', GC_Extend), ('\u{1cf8}', '\u{1cf9}', GC_Extend), - ('\u{1dc0}', '\u{1df5}', GC_Extend), ('\u{1dfc}', '\u{1dff}', GC_Extend), ('\u{200b}', - '\u{200b}', GC_Control), ('\u{200c}', '\u{200d}', GC_Extend), ('\u{200e}', '\u{200f}', - GC_Control), ('\u{2028}', '\u{202e}', GC_Control), ('\u{2060}', '\u{206f}', GC_Control), - ('\u{20d0}', '\u{20dc}', GC_Extend), ('\u{20dd}', '\u{20e0}', GC_Extend), ('\u{20e1}', - '\u{20e1}', GC_Extend), ('\u{20e2}', '\u{20e4}', GC_Extend), ('\u{20e5}', '\u{20f0}', - GC_Extend), ('\u{2cef}', '\u{2cf1}', GC_Extend), ('\u{2d7f}', '\u{2d7f}', GC_Extend), - ('\u{2de0}', '\u{2dff}', GC_Extend), ('\u{302a}', '\u{302d}', GC_Extend), ('\u{302e}', - '\u{302f}', GC_Extend), ('\u{3099}', '\u{309a}', GC_Extend), ('\u{a66f}', '\u{a66f}', - GC_Extend), ('\u{a670}', '\u{a672}', GC_Extend), ('\u{a674}', '\u{a67d}', GC_Extend), - ('\u{a69f}', '\u{a69f}', GC_Extend), ('\u{a6f0}', '\u{a6f1}', GC_Extend), ('\u{a802}', - '\u{a802}', GC_Extend), ('\u{a806}', '\u{a806}', GC_Extend), ('\u{a80b}', '\u{a80b}', - GC_Extend), ('\u{a823}', '\u{a824}', GC_SpacingMark), ('\u{a825}', '\u{a826}', GC_Extend), - ('\u{a827}', '\u{a827}', GC_SpacingMark), ('\u{a880}', '\u{a881}', GC_SpacingMark), - ('\u{a8b4}', '\u{a8c3}', GC_SpacingMark), ('\u{a8c4}', '\u{a8c4}', GC_Extend), ('\u{a8e0}', - '\u{a8f1}', GC_Extend), ('\u{a926}', '\u{a92d}', GC_Extend), ('\u{a947}', '\u{a951}', - GC_Extend), ('\u{a952}', '\u{a953}', GC_SpacingMark), ('\u{a960}', '\u{a97c}', GC_L), - ('\u{a980}', '\u{a982}', GC_Extend), ('\u{a983}', '\u{a983}', GC_SpacingMark), ('\u{a9b3}', - '\u{a9b3}', GC_Extend), ('\u{a9b4}', '\u{a9b5}', GC_SpacingMark), ('\u{a9b6}', '\u{a9b9}', - GC_Extend), ('\u{a9ba}', '\u{a9bb}', GC_SpacingMark), ('\u{a9bc}', '\u{a9bc}', GC_Extend), - ('\u{a9bd}', '\u{a9c0}', GC_SpacingMark), ('\u{a9e5}', '\u{a9e5}', GC_Extend), ('\u{aa29}', - '\u{aa2e}', GC_Extend), ('\u{aa2f}', '\u{aa30}', GC_SpacingMark), ('\u{aa31}', '\u{aa32}', - GC_Extend), ('\u{aa33}', '\u{aa34}', GC_SpacingMark), ('\u{aa35}', '\u{aa36}', GC_Extend), - ('\u{aa43}', '\u{aa43}', GC_Extend), ('\u{aa4c}', '\u{aa4c}', GC_Extend), ('\u{aa4d}', - '\u{aa4d}', GC_SpacingMark), ('\u{aa7b}', '\u{aa7b}', GC_SpacingMark), ('\u{aa7c}', - '\u{aa7c}', GC_Extend), ('\u{aa7d}', '\u{aa7d}', GC_SpacingMark), ('\u{aab0}', '\u{aab0}', - GC_Extend), ('\u{aab2}', '\u{aab4}', GC_Extend), ('\u{aab7}', '\u{aab8}', GC_Extend), - ('\u{aabe}', '\u{aabf}', GC_Extend), ('\u{aac1}', '\u{aac1}', GC_Extend), ('\u{aaeb}', - '\u{aaeb}', GC_SpacingMark), ('\u{aaec}', '\u{aaed}', GC_Extend), ('\u{aaee}', '\u{aaef}', - GC_SpacingMark), ('\u{aaf5}', '\u{aaf5}', GC_SpacingMark), ('\u{aaf6}', '\u{aaf6}', - GC_Extend), ('\u{abe3}', '\u{abe4}', GC_SpacingMark), ('\u{abe5}', '\u{abe5}', GC_Extend), - ('\u{abe6}', '\u{abe7}', GC_SpacingMark), ('\u{abe8}', '\u{abe8}', GC_Extend), ('\u{abe9}', - '\u{abea}', GC_SpacingMark), ('\u{abec}', '\u{abec}', GC_SpacingMark), ('\u{abed}', - '\u{abed}', GC_Extend), ('\u{ac00}', '\u{ac00}', GC_LV), ('\u{ac01}', '\u{ac1b}', GC_LVT), - ('\u{ac1c}', '\u{ac1c}', GC_LV), ('\u{ac1d}', '\u{ac37}', GC_LVT), ('\u{ac38}', '\u{ac38}', - GC_LV), ('\u{ac39}', '\u{ac53}', GC_LVT), ('\u{ac54}', '\u{ac54}', GC_LV), ('\u{ac55}', - '\u{ac6f}', GC_LVT), ('\u{ac70}', '\u{ac70}', GC_LV), ('\u{ac71}', '\u{ac8b}', GC_LVT), - ('\u{ac8c}', '\u{ac8c}', GC_LV), ('\u{ac8d}', '\u{aca7}', GC_LVT), ('\u{aca8}', '\u{aca8}', - GC_LV), ('\u{aca9}', '\u{acc3}', GC_LVT), ('\u{acc4}', '\u{acc4}', GC_LV), ('\u{acc5}', - '\u{acdf}', GC_LVT), ('\u{ace0}', '\u{ace0}', GC_LV), ('\u{ace1}', '\u{acfb}', GC_LVT), - ('\u{acfc}', '\u{acfc}', GC_LV), ('\u{acfd}', '\u{ad17}', GC_LVT), ('\u{ad18}', '\u{ad18}', - GC_LV), ('\u{ad19}', '\u{ad33}', GC_LVT), ('\u{ad34}', '\u{ad34}', GC_LV), ('\u{ad35}', - '\u{ad4f}', GC_LVT), ('\u{ad50}', '\u{ad50}', GC_LV), ('\u{ad51}', '\u{ad6b}', GC_LVT), - ('\u{ad6c}', '\u{ad6c}', GC_LV), ('\u{ad6d}', '\u{ad87}', GC_LVT), ('\u{ad88}', '\u{ad88}', - GC_LV), ('\u{ad89}', '\u{ada3}', GC_LVT), ('\u{ada4}', '\u{ada4}', GC_LV), ('\u{ada5}', - '\u{adbf}', GC_LVT), ('\u{adc0}', '\u{adc0}', GC_LV), ('\u{adc1}', '\u{addb}', GC_LVT), - ('\u{addc}', '\u{addc}', GC_LV), ('\u{addd}', '\u{adf7}', GC_LVT), ('\u{adf8}', '\u{adf8}', - GC_LV), ('\u{adf9}', '\u{ae13}', GC_LVT), ('\u{ae14}', '\u{ae14}', GC_LV), ('\u{ae15}', - '\u{ae2f}', GC_LVT), ('\u{ae30}', '\u{ae30}', GC_LV), ('\u{ae31}', '\u{ae4b}', GC_LVT), - ('\u{ae4c}', '\u{ae4c}', GC_LV), ('\u{ae4d}', '\u{ae67}', GC_LVT), ('\u{ae68}', '\u{ae68}', - GC_LV), ('\u{ae69}', '\u{ae83}', GC_LVT), ('\u{ae84}', '\u{ae84}', GC_LV), ('\u{ae85}', - '\u{ae9f}', GC_LVT), ('\u{aea0}', '\u{aea0}', GC_LV), ('\u{aea1}', '\u{aebb}', GC_LVT), - ('\u{aebc}', '\u{aebc}', GC_LV), ('\u{aebd}', '\u{aed7}', GC_LVT), ('\u{aed8}', '\u{aed8}', - GC_LV), ('\u{aed9}', '\u{aef3}', GC_LVT), ('\u{aef4}', '\u{aef4}', GC_LV), ('\u{aef5}', - '\u{af0f}', GC_LVT), ('\u{af10}', '\u{af10}', GC_LV), ('\u{af11}', '\u{af2b}', GC_LVT), - ('\u{af2c}', '\u{af2c}', GC_LV), ('\u{af2d}', '\u{af47}', GC_LVT), ('\u{af48}', '\u{af48}', - GC_LV), ('\u{af49}', '\u{af63}', GC_LVT), ('\u{af64}', '\u{af64}', GC_LV), ('\u{af65}', - '\u{af7f}', GC_LVT), ('\u{af80}', '\u{af80}', GC_LV), ('\u{af81}', '\u{af9b}', GC_LVT), - ('\u{af9c}', '\u{af9c}', GC_LV), ('\u{af9d}', '\u{afb7}', GC_LVT), ('\u{afb8}', '\u{afb8}', - GC_LV), ('\u{afb9}', '\u{afd3}', GC_LVT), ('\u{afd4}', '\u{afd4}', GC_LV), ('\u{afd5}', - '\u{afef}', GC_LVT), ('\u{aff0}', '\u{aff0}', GC_LV), ('\u{aff1}', '\u{b00b}', GC_LVT), - ('\u{b00c}', '\u{b00c}', GC_LV), ('\u{b00d}', '\u{b027}', GC_LVT), ('\u{b028}', '\u{b028}', - GC_LV), ('\u{b029}', '\u{b043}', GC_LVT), ('\u{b044}', '\u{b044}', GC_LV), ('\u{b045}', - '\u{b05f}', GC_LVT), ('\u{b060}', '\u{b060}', GC_LV), ('\u{b061}', '\u{b07b}', GC_LVT), - ('\u{b07c}', '\u{b07c}', GC_LV), ('\u{b07d}', '\u{b097}', GC_LVT), ('\u{b098}', '\u{b098}', - GC_LV), ('\u{b099}', '\u{b0b3}', GC_LVT), ('\u{b0b4}', '\u{b0b4}', GC_LV), ('\u{b0b5}', - '\u{b0cf}', GC_LVT), ('\u{b0d0}', '\u{b0d0}', GC_LV), ('\u{b0d1}', '\u{b0eb}', GC_LVT), - ('\u{b0ec}', '\u{b0ec}', GC_LV), ('\u{b0ed}', '\u{b107}', GC_LVT), ('\u{b108}', '\u{b108}', - GC_LV), ('\u{b109}', '\u{b123}', GC_LVT), ('\u{b124}', '\u{b124}', GC_LV), ('\u{b125}', - '\u{b13f}', GC_LVT), ('\u{b140}', '\u{b140}', GC_LV), ('\u{b141}', '\u{b15b}', GC_LVT), - ('\u{b15c}', '\u{b15c}', GC_LV), ('\u{b15d}', '\u{b177}', GC_LVT), ('\u{b178}', '\u{b178}', - GC_LV), ('\u{b179}', '\u{b193}', GC_LVT), ('\u{b194}', '\u{b194}', GC_LV), ('\u{b195}', - '\u{b1af}', GC_LVT), ('\u{b1b0}', '\u{b1b0}', GC_LV), ('\u{b1b1}', '\u{b1cb}', GC_LVT), - ('\u{b1cc}', '\u{b1cc}', GC_LV), ('\u{b1cd}', '\u{b1e7}', GC_LVT), ('\u{b1e8}', '\u{b1e8}', - GC_LV), ('\u{b1e9}', '\u{b203}', GC_LVT), ('\u{b204}', '\u{b204}', GC_LV), ('\u{b205}', - '\u{b21f}', GC_LVT), ('\u{b220}', '\u{b220}', GC_LV), ('\u{b221}', '\u{b23b}', GC_LVT), - ('\u{b23c}', '\u{b23c}', GC_LV), ('\u{b23d}', '\u{b257}', GC_LVT), ('\u{b258}', '\u{b258}', - GC_LV), ('\u{b259}', '\u{b273}', GC_LVT), ('\u{b274}', '\u{b274}', GC_LV), ('\u{b275}', - '\u{b28f}', GC_LVT), ('\u{b290}', '\u{b290}', GC_LV), ('\u{b291}', '\u{b2ab}', GC_LVT), - ('\u{b2ac}', '\u{b2ac}', GC_LV), ('\u{b2ad}', '\u{b2c7}', GC_LVT), ('\u{b2c8}', '\u{b2c8}', - GC_LV), ('\u{b2c9}', '\u{b2e3}', GC_LVT), ('\u{b2e4}', '\u{b2e4}', GC_LV), ('\u{b2e5}', - '\u{b2ff}', GC_LVT), ('\u{b300}', '\u{b300}', GC_LV), ('\u{b301}', '\u{b31b}', GC_LVT), - ('\u{b31c}', '\u{b31c}', GC_LV), ('\u{b31d}', '\u{b337}', GC_LVT), ('\u{b338}', '\u{b338}', - GC_LV), ('\u{b339}', '\u{b353}', GC_LVT), ('\u{b354}', '\u{b354}', GC_LV), ('\u{b355}', - '\u{b36f}', GC_LVT), ('\u{b370}', '\u{b370}', GC_LV), ('\u{b371}', '\u{b38b}', GC_LVT), - ('\u{b38c}', '\u{b38c}', GC_LV), ('\u{b38d}', '\u{b3a7}', GC_LVT), ('\u{b3a8}', '\u{b3a8}', - GC_LV), ('\u{b3a9}', '\u{b3c3}', GC_LVT), ('\u{b3c4}', '\u{b3c4}', GC_LV), ('\u{b3c5}', - '\u{b3df}', GC_LVT), ('\u{b3e0}', '\u{b3e0}', GC_LV), ('\u{b3e1}', '\u{b3fb}', GC_LVT), - ('\u{b3fc}', '\u{b3fc}', GC_LV), ('\u{b3fd}', '\u{b417}', GC_LVT), ('\u{b418}', '\u{b418}', - GC_LV), ('\u{b419}', '\u{b433}', GC_LVT), ('\u{b434}', '\u{b434}', GC_LV), ('\u{b435}', - '\u{b44f}', GC_LVT), ('\u{b450}', '\u{b450}', GC_LV), ('\u{b451}', '\u{b46b}', GC_LVT), - ('\u{b46c}', '\u{b46c}', GC_LV), ('\u{b46d}', '\u{b487}', GC_LVT), ('\u{b488}', '\u{b488}', - GC_LV), ('\u{b489}', '\u{b4a3}', GC_LVT), ('\u{b4a4}', '\u{b4a4}', GC_LV), ('\u{b4a5}', - '\u{b4bf}', GC_LVT), ('\u{b4c0}', '\u{b4c0}', GC_LV), ('\u{b4c1}', '\u{b4db}', GC_LVT), - ('\u{b4dc}', '\u{b4dc}', GC_LV), ('\u{b4dd}', '\u{b4f7}', GC_LVT), ('\u{b4f8}', '\u{b4f8}', - GC_LV), ('\u{b4f9}', '\u{b513}', GC_LVT), ('\u{b514}', '\u{b514}', GC_LV), ('\u{b515}', - '\u{b52f}', GC_LVT), ('\u{b530}', '\u{b530}', GC_LV), ('\u{b531}', '\u{b54b}', GC_LVT), - ('\u{b54c}', '\u{b54c}', GC_LV), ('\u{b54d}', '\u{b567}', GC_LVT), ('\u{b568}', '\u{b568}', - GC_LV), ('\u{b569}', '\u{b583}', GC_LVT), ('\u{b584}', '\u{b584}', GC_LV), ('\u{b585}', - '\u{b59f}', GC_LVT), ('\u{b5a0}', '\u{b5a0}', GC_LV), ('\u{b5a1}', '\u{b5bb}', GC_LVT), - ('\u{b5bc}', '\u{b5bc}', GC_LV), ('\u{b5bd}', '\u{b5d7}', GC_LVT), ('\u{b5d8}', '\u{b5d8}', - GC_LV), ('\u{b5d9}', '\u{b5f3}', GC_LVT), ('\u{b5f4}', '\u{b5f4}', GC_LV), ('\u{b5f5}', - '\u{b60f}', GC_LVT), ('\u{b610}', '\u{b610}', GC_LV), ('\u{b611}', '\u{b62b}', GC_LVT), - ('\u{b62c}', '\u{b62c}', GC_LV), ('\u{b62d}', '\u{b647}', GC_LVT), ('\u{b648}', '\u{b648}', - GC_LV), ('\u{b649}', '\u{b663}', GC_LVT), ('\u{b664}', '\u{b664}', GC_LV), ('\u{b665}', - '\u{b67f}', GC_LVT), ('\u{b680}', '\u{b680}', GC_LV), ('\u{b681}', '\u{b69b}', GC_LVT), - ('\u{b69c}', '\u{b69c}', GC_LV), ('\u{b69d}', '\u{b6b7}', GC_LVT), ('\u{b6b8}', '\u{b6b8}', - GC_LV), ('\u{b6b9}', '\u{b6d3}', GC_LVT), ('\u{b6d4}', '\u{b6d4}', GC_LV), ('\u{b6d5}', - '\u{b6ef}', GC_LVT), ('\u{b6f0}', '\u{b6f0}', GC_LV), ('\u{b6f1}', '\u{b70b}', GC_LVT), - ('\u{b70c}', '\u{b70c}', GC_LV), ('\u{b70d}', '\u{b727}', GC_LVT), ('\u{b728}', '\u{b728}', - GC_LV), ('\u{b729}', '\u{b743}', GC_LVT), ('\u{b744}', '\u{b744}', GC_LV), ('\u{b745}', - '\u{b75f}', GC_LVT), ('\u{b760}', '\u{b760}', GC_LV), ('\u{b761}', '\u{b77b}', GC_LVT), - ('\u{b77c}', '\u{b77c}', GC_LV), ('\u{b77d}', '\u{b797}', GC_LVT), ('\u{b798}', '\u{b798}', - GC_LV), ('\u{b799}', '\u{b7b3}', GC_LVT), ('\u{b7b4}', '\u{b7b4}', GC_LV), ('\u{b7b5}', - '\u{b7cf}', GC_LVT), ('\u{b7d0}', '\u{b7d0}', GC_LV), ('\u{b7d1}', '\u{b7eb}', GC_LVT), - ('\u{b7ec}', '\u{b7ec}', GC_LV), ('\u{b7ed}', '\u{b807}', GC_LVT), ('\u{b808}', '\u{b808}', - GC_LV), ('\u{b809}', '\u{b823}', GC_LVT), ('\u{b824}', '\u{b824}', GC_LV), ('\u{b825}', - '\u{b83f}', GC_LVT), ('\u{b840}', '\u{b840}', GC_LV), ('\u{b841}', '\u{b85b}', GC_LVT), - ('\u{b85c}', '\u{b85c}', GC_LV), ('\u{b85d}', '\u{b877}', GC_LVT), ('\u{b878}', '\u{b878}', - GC_LV), ('\u{b879}', '\u{b893}', GC_LVT), ('\u{b894}', '\u{b894}', GC_LV), ('\u{b895}', - '\u{b8af}', GC_LVT), ('\u{b8b0}', '\u{b8b0}', GC_LV), ('\u{b8b1}', '\u{b8cb}', GC_LVT), - ('\u{b8cc}', '\u{b8cc}', GC_LV), ('\u{b8cd}', '\u{b8e7}', GC_LVT), ('\u{b8e8}', '\u{b8e8}', - GC_LV), ('\u{b8e9}', '\u{b903}', GC_LVT), ('\u{b904}', '\u{b904}', GC_LV), ('\u{b905}', - '\u{b91f}', GC_LVT), ('\u{b920}', '\u{b920}', GC_LV), ('\u{b921}', '\u{b93b}', GC_LVT), - ('\u{b93c}', '\u{b93c}', GC_LV), ('\u{b93d}', '\u{b957}', GC_LVT), ('\u{b958}', '\u{b958}', - GC_LV), ('\u{b959}', '\u{b973}', GC_LVT), ('\u{b974}', '\u{b974}', GC_LV), ('\u{b975}', - '\u{b98f}', GC_LVT), ('\u{b990}', '\u{b990}', GC_LV), ('\u{b991}', '\u{b9ab}', GC_LVT), - ('\u{b9ac}', '\u{b9ac}', GC_LV), ('\u{b9ad}', '\u{b9c7}', GC_LVT), ('\u{b9c8}', '\u{b9c8}', - GC_LV), ('\u{b9c9}', '\u{b9e3}', GC_LVT), ('\u{b9e4}', '\u{b9e4}', GC_LV), ('\u{b9e5}', - '\u{b9ff}', GC_LVT), ('\u{ba00}', '\u{ba00}', GC_LV), ('\u{ba01}', '\u{ba1b}', GC_LVT), - ('\u{ba1c}', '\u{ba1c}', GC_LV), ('\u{ba1d}', '\u{ba37}', GC_LVT), ('\u{ba38}', '\u{ba38}', - GC_LV), ('\u{ba39}', '\u{ba53}', GC_LVT), ('\u{ba54}', '\u{ba54}', GC_LV), ('\u{ba55}', - '\u{ba6f}', GC_LVT), ('\u{ba70}', '\u{ba70}', GC_LV), ('\u{ba71}', '\u{ba8b}', GC_LVT), - ('\u{ba8c}', '\u{ba8c}', GC_LV), ('\u{ba8d}', '\u{baa7}', GC_LVT), ('\u{baa8}', '\u{baa8}', - GC_LV), ('\u{baa9}', '\u{bac3}', GC_LVT), ('\u{bac4}', '\u{bac4}', GC_LV), ('\u{bac5}', - '\u{badf}', GC_LVT), ('\u{bae0}', '\u{bae0}', GC_LV), ('\u{bae1}', '\u{bafb}', GC_LVT), - ('\u{bafc}', '\u{bafc}', GC_LV), ('\u{bafd}', '\u{bb17}', GC_LVT), ('\u{bb18}', '\u{bb18}', - GC_LV), ('\u{bb19}', '\u{bb33}', GC_LVT), ('\u{bb34}', '\u{bb34}', GC_LV), ('\u{bb35}', - '\u{bb4f}', GC_LVT), ('\u{bb50}', '\u{bb50}', GC_LV), ('\u{bb51}', '\u{bb6b}', GC_LVT), - ('\u{bb6c}', '\u{bb6c}', GC_LV), ('\u{bb6d}', '\u{bb87}', GC_LVT), ('\u{bb88}', '\u{bb88}', - GC_LV), ('\u{bb89}', '\u{bba3}', GC_LVT), ('\u{bba4}', '\u{bba4}', GC_LV), ('\u{bba5}', - '\u{bbbf}', GC_LVT), ('\u{bbc0}', '\u{bbc0}', GC_LV), ('\u{bbc1}', '\u{bbdb}', GC_LVT), - ('\u{bbdc}', '\u{bbdc}', GC_LV), ('\u{bbdd}', '\u{bbf7}', GC_LVT), ('\u{bbf8}', '\u{bbf8}', - GC_LV), ('\u{bbf9}', '\u{bc13}', GC_LVT), ('\u{bc14}', '\u{bc14}', GC_LV), ('\u{bc15}', - '\u{bc2f}', GC_LVT), ('\u{bc30}', '\u{bc30}', GC_LV), ('\u{bc31}', '\u{bc4b}', GC_LVT), - ('\u{bc4c}', '\u{bc4c}', GC_LV), ('\u{bc4d}', '\u{bc67}', GC_LVT), ('\u{bc68}', '\u{bc68}', - GC_LV), ('\u{bc69}', '\u{bc83}', GC_LVT), ('\u{bc84}', '\u{bc84}', GC_LV), ('\u{bc85}', - '\u{bc9f}', GC_LVT), ('\u{bca0}', '\u{bca0}', GC_LV), ('\u{bca1}', '\u{bcbb}', GC_LVT), - ('\u{bcbc}', '\u{bcbc}', GC_LV), ('\u{bcbd}', '\u{bcd7}', GC_LVT), ('\u{bcd8}', '\u{bcd8}', - GC_LV), ('\u{bcd9}', '\u{bcf3}', GC_LVT), ('\u{bcf4}', '\u{bcf4}', GC_LV), ('\u{bcf5}', - '\u{bd0f}', GC_LVT), ('\u{bd10}', '\u{bd10}', GC_LV), ('\u{bd11}', '\u{bd2b}', GC_LVT), - ('\u{bd2c}', '\u{bd2c}', GC_LV), ('\u{bd2d}', '\u{bd47}', GC_LVT), ('\u{bd48}', '\u{bd48}', - GC_LV), ('\u{bd49}', '\u{bd63}', GC_LVT), ('\u{bd64}', '\u{bd64}', GC_LV), ('\u{bd65}', - '\u{bd7f}', GC_LVT), ('\u{bd80}', '\u{bd80}', GC_LV), ('\u{bd81}', '\u{bd9b}', GC_LVT), - ('\u{bd9c}', '\u{bd9c}', GC_LV), ('\u{bd9d}', '\u{bdb7}', GC_LVT), ('\u{bdb8}', '\u{bdb8}', - GC_LV), ('\u{bdb9}', '\u{bdd3}', GC_LVT), ('\u{bdd4}', '\u{bdd4}', GC_LV), ('\u{bdd5}', - '\u{bdef}', GC_LVT), ('\u{bdf0}', '\u{bdf0}', GC_LV), ('\u{bdf1}', '\u{be0b}', GC_LVT), - ('\u{be0c}', '\u{be0c}', GC_LV), ('\u{be0d}', '\u{be27}', GC_LVT), ('\u{be28}', '\u{be28}', - GC_LV), ('\u{be29}', '\u{be43}', GC_LVT), ('\u{be44}', '\u{be44}', GC_LV), ('\u{be45}', - '\u{be5f}', GC_LVT), ('\u{be60}', '\u{be60}', GC_LV), ('\u{be61}', '\u{be7b}', GC_LVT), - ('\u{be7c}', '\u{be7c}', GC_LV), ('\u{be7d}', '\u{be97}', GC_LVT), ('\u{be98}', '\u{be98}', - GC_LV), ('\u{be99}', '\u{beb3}', GC_LVT), ('\u{beb4}', '\u{beb4}', GC_LV), ('\u{beb5}', - '\u{becf}', GC_LVT), ('\u{bed0}', '\u{bed0}', GC_LV), ('\u{bed1}', '\u{beeb}', GC_LVT), - ('\u{beec}', '\u{beec}', GC_LV), ('\u{beed}', '\u{bf07}', GC_LVT), ('\u{bf08}', '\u{bf08}', - GC_LV), ('\u{bf09}', '\u{bf23}', GC_LVT), ('\u{bf24}', '\u{bf24}', GC_LV), ('\u{bf25}', - '\u{bf3f}', GC_LVT), ('\u{bf40}', '\u{bf40}', GC_LV), ('\u{bf41}', '\u{bf5b}', GC_LVT), - ('\u{bf5c}', '\u{bf5c}', GC_LV), ('\u{bf5d}', '\u{bf77}', GC_LVT), ('\u{bf78}', '\u{bf78}', - GC_LV), ('\u{bf79}', '\u{bf93}', GC_LVT), ('\u{bf94}', '\u{bf94}', GC_LV), ('\u{bf95}', - '\u{bfaf}', GC_LVT), ('\u{bfb0}', '\u{bfb0}', GC_LV), ('\u{bfb1}', '\u{bfcb}', GC_LVT), - ('\u{bfcc}', '\u{bfcc}', GC_LV), ('\u{bfcd}', '\u{bfe7}', GC_LVT), ('\u{bfe8}', '\u{bfe8}', - GC_LV), ('\u{bfe9}', '\u{c003}', GC_LVT), ('\u{c004}', '\u{c004}', GC_LV), ('\u{c005}', - '\u{c01f}', GC_LVT), ('\u{c020}', '\u{c020}', GC_LV), ('\u{c021}', '\u{c03b}', GC_LVT), - ('\u{c03c}', '\u{c03c}', GC_LV), ('\u{c03d}', '\u{c057}', GC_LVT), ('\u{c058}', '\u{c058}', - GC_LV), ('\u{c059}', '\u{c073}', GC_LVT), ('\u{c074}', '\u{c074}', GC_LV), ('\u{c075}', - '\u{c08f}', GC_LVT), ('\u{c090}', '\u{c090}', GC_LV), ('\u{c091}', '\u{c0ab}', GC_LVT), - ('\u{c0ac}', '\u{c0ac}', GC_LV), ('\u{c0ad}', '\u{c0c7}', GC_LVT), ('\u{c0c8}', '\u{c0c8}', - GC_LV), ('\u{c0c9}', '\u{c0e3}', GC_LVT), ('\u{c0e4}', '\u{c0e4}', GC_LV), ('\u{c0e5}', - '\u{c0ff}', GC_LVT), ('\u{c100}', '\u{c100}', GC_LV), ('\u{c101}', '\u{c11b}', GC_LVT), - ('\u{c11c}', '\u{c11c}', GC_LV), ('\u{c11d}', '\u{c137}', GC_LVT), ('\u{c138}', '\u{c138}', - GC_LV), ('\u{c139}', '\u{c153}', GC_LVT), ('\u{c154}', '\u{c154}', GC_LV), ('\u{c155}', - '\u{c16f}', GC_LVT), ('\u{c170}', '\u{c170}', GC_LV), ('\u{c171}', '\u{c18b}', GC_LVT), - ('\u{c18c}', '\u{c18c}', GC_LV), ('\u{c18d}', '\u{c1a7}', GC_LVT), ('\u{c1a8}', '\u{c1a8}', - GC_LV), ('\u{c1a9}', '\u{c1c3}', GC_LVT), ('\u{c1c4}', '\u{c1c4}', GC_LV), ('\u{c1c5}', - '\u{c1df}', GC_LVT), ('\u{c1e0}', '\u{c1e0}', GC_LV), ('\u{c1e1}', '\u{c1fb}', GC_LVT), - ('\u{c1fc}', '\u{c1fc}', GC_LV), ('\u{c1fd}', '\u{c217}', GC_LVT), ('\u{c218}', '\u{c218}', - GC_LV), ('\u{c219}', '\u{c233}', GC_LVT), ('\u{c234}', '\u{c234}', GC_LV), ('\u{c235}', - '\u{c24f}', GC_LVT), ('\u{c250}', '\u{c250}', GC_LV), ('\u{c251}', '\u{c26b}', GC_LVT), - ('\u{c26c}', '\u{c26c}', GC_LV), ('\u{c26d}', '\u{c287}', GC_LVT), ('\u{c288}', '\u{c288}', - GC_LV), ('\u{c289}', '\u{c2a3}', GC_LVT), ('\u{c2a4}', '\u{c2a4}', GC_LV), ('\u{c2a5}', - '\u{c2bf}', GC_LVT), ('\u{c2c0}', '\u{c2c0}', GC_LV), ('\u{c2c1}', '\u{c2db}', GC_LVT), - ('\u{c2dc}', '\u{c2dc}', GC_LV), ('\u{c2dd}', '\u{c2f7}', GC_LVT), ('\u{c2f8}', '\u{c2f8}', - GC_LV), ('\u{c2f9}', '\u{c313}', GC_LVT), ('\u{c314}', '\u{c314}', GC_LV), ('\u{c315}', - '\u{c32f}', GC_LVT), ('\u{c330}', '\u{c330}', GC_LV), ('\u{c331}', '\u{c34b}', GC_LVT), - ('\u{c34c}', '\u{c34c}', GC_LV), ('\u{c34d}', '\u{c367}', GC_LVT), ('\u{c368}', '\u{c368}', - GC_LV), ('\u{c369}', '\u{c383}', GC_LVT), ('\u{c384}', '\u{c384}', GC_LV), ('\u{c385}', - '\u{c39f}', GC_LVT), ('\u{c3a0}', '\u{c3a0}', GC_LV), ('\u{c3a1}', '\u{c3bb}', GC_LVT), - ('\u{c3bc}', '\u{c3bc}', GC_LV), ('\u{c3bd}', '\u{c3d7}', GC_LVT), ('\u{c3d8}', '\u{c3d8}', - GC_LV), ('\u{c3d9}', '\u{c3f3}', GC_LVT), ('\u{c3f4}', '\u{c3f4}', GC_LV), ('\u{c3f5}', - '\u{c40f}', GC_LVT), ('\u{c410}', '\u{c410}', GC_LV), ('\u{c411}', '\u{c42b}', GC_LVT), - ('\u{c42c}', '\u{c42c}', GC_LV), ('\u{c42d}', '\u{c447}', GC_LVT), ('\u{c448}', '\u{c448}', - GC_LV), ('\u{c449}', '\u{c463}', GC_LVT), ('\u{c464}', '\u{c464}', GC_LV), ('\u{c465}', - '\u{c47f}', GC_LVT), ('\u{c480}', '\u{c480}', GC_LV), ('\u{c481}', '\u{c49b}', GC_LVT), - ('\u{c49c}', '\u{c49c}', GC_LV), ('\u{c49d}', '\u{c4b7}', GC_LVT), ('\u{c4b8}', '\u{c4b8}', - GC_LV), ('\u{c4b9}', '\u{c4d3}', GC_LVT), ('\u{c4d4}', '\u{c4d4}', GC_LV), ('\u{c4d5}', - '\u{c4ef}', GC_LVT), ('\u{c4f0}', '\u{c4f0}', GC_LV), ('\u{c4f1}', '\u{c50b}', GC_LVT), - ('\u{c50c}', '\u{c50c}', GC_LV), ('\u{c50d}', '\u{c527}', GC_LVT), ('\u{c528}', '\u{c528}', - GC_LV), ('\u{c529}', '\u{c543}', GC_LVT), ('\u{c544}', '\u{c544}', GC_LV), ('\u{c545}', - '\u{c55f}', GC_LVT), ('\u{c560}', '\u{c560}', GC_LV), ('\u{c561}', '\u{c57b}', GC_LVT), - ('\u{c57c}', '\u{c57c}', GC_LV), ('\u{c57d}', '\u{c597}', GC_LVT), ('\u{c598}', '\u{c598}', - GC_LV), ('\u{c599}', '\u{c5b3}', GC_LVT), ('\u{c5b4}', '\u{c5b4}', GC_LV), ('\u{c5b5}', - '\u{c5cf}', GC_LVT), ('\u{c5d0}', '\u{c5d0}', GC_LV), ('\u{c5d1}', '\u{c5eb}', GC_LVT), - ('\u{c5ec}', '\u{c5ec}', GC_LV), ('\u{c5ed}', '\u{c607}', GC_LVT), ('\u{c608}', '\u{c608}', - GC_LV), ('\u{c609}', '\u{c623}', GC_LVT), ('\u{c624}', '\u{c624}', GC_LV), ('\u{c625}', - '\u{c63f}', GC_LVT), ('\u{c640}', '\u{c640}', GC_LV), ('\u{c641}', '\u{c65b}', GC_LVT), - ('\u{c65c}', '\u{c65c}', GC_LV), ('\u{c65d}', '\u{c677}', GC_LVT), ('\u{c678}', '\u{c678}', - GC_LV), ('\u{c679}', '\u{c693}', GC_LVT), ('\u{c694}', '\u{c694}', GC_LV), ('\u{c695}', - '\u{c6af}', GC_LVT), ('\u{c6b0}', '\u{c6b0}', GC_LV), ('\u{c6b1}', '\u{c6cb}', GC_LVT), - ('\u{c6cc}', '\u{c6cc}', GC_LV), ('\u{c6cd}', '\u{c6e7}', GC_LVT), ('\u{c6e8}', '\u{c6e8}', - GC_LV), ('\u{c6e9}', '\u{c703}', GC_LVT), ('\u{c704}', '\u{c704}', GC_LV), ('\u{c705}', - '\u{c71f}', GC_LVT), ('\u{c720}', '\u{c720}', GC_LV), ('\u{c721}', '\u{c73b}', GC_LVT), - ('\u{c73c}', '\u{c73c}', GC_LV), ('\u{c73d}', '\u{c757}', GC_LVT), ('\u{c758}', '\u{c758}', - GC_LV), ('\u{c759}', '\u{c773}', GC_LVT), ('\u{c774}', '\u{c774}', GC_LV), ('\u{c775}', - '\u{c78f}', GC_LVT), ('\u{c790}', '\u{c790}', GC_LV), ('\u{c791}', '\u{c7ab}', GC_LVT), - ('\u{c7ac}', '\u{c7ac}', GC_LV), ('\u{c7ad}', '\u{c7c7}', GC_LVT), ('\u{c7c8}', '\u{c7c8}', - GC_LV), ('\u{c7c9}', '\u{c7e3}', GC_LVT), ('\u{c7e4}', '\u{c7e4}', GC_LV), ('\u{c7e5}', - '\u{c7ff}', GC_LVT), ('\u{c800}', '\u{c800}', GC_LV), ('\u{c801}', '\u{c81b}', GC_LVT), - ('\u{c81c}', '\u{c81c}', GC_LV), ('\u{c81d}', '\u{c837}', GC_LVT), ('\u{c838}', '\u{c838}', - GC_LV), ('\u{c839}', '\u{c853}', GC_LVT), ('\u{c854}', '\u{c854}', GC_LV), ('\u{c855}', - '\u{c86f}', GC_LVT), ('\u{c870}', '\u{c870}', GC_LV), ('\u{c871}', '\u{c88b}', GC_LVT), - ('\u{c88c}', '\u{c88c}', GC_LV), ('\u{c88d}', '\u{c8a7}', GC_LVT), ('\u{c8a8}', '\u{c8a8}', - GC_LV), ('\u{c8a9}', '\u{c8c3}', GC_LVT), ('\u{c8c4}', '\u{c8c4}', GC_LV), ('\u{c8c5}', - '\u{c8df}', GC_LVT), ('\u{c8e0}', '\u{c8e0}', GC_LV), ('\u{c8e1}', '\u{c8fb}', GC_LVT), - ('\u{c8fc}', '\u{c8fc}', GC_LV), ('\u{c8fd}', '\u{c917}', GC_LVT), ('\u{c918}', '\u{c918}', - GC_LV), ('\u{c919}', '\u{c933}', GC_LVT), ('\u{c934}', '\u{c934}', GC_LV), ('\u{c935}', - '\u{c94f}', GC_LVT), ('\u{c950}', '\u{c950}', GC_LV), ('\u{c951}', '\u{c96b}', GC_LVT), - ('\u{c96c}', '\u{c96c}', GC_LV), ('\u{c96d}', '\u{c987}', GC_LVT), ('\u{c988}', '\u{c988}', - GC_LV), ('\u{c989}', '\u{c9a3}', GC_LVT), ('\u{c9a4}', '\u{c9a4}', GC_LV), ('\u{c9a5}', - '\u{c9bf}', GC_LVT), ('\u{c9c0}', '\u{c9c0}', GC_LV), ('\u{c9c1}', '\u{c9db}', GC_LVT), - ('\u{c9dc}', '\u{c9dc}', GC_LV), ('\u{c9dd}', '\u{c9f7}', GC_LVT), ('\u{c9f8}', '\u{c9f8}', - GC_LV), ('\u{c9f9}', '\u{ca13}', GC_LVT), ('\u{ca14}', '\u{ca14}', GC_LV), ('\u{ca15}', - '\u{ca2f}', GC_LVT), ('\u{ca30}', '\u{ca30}', GC_LV), ('\u{ca31}', '\u{ca4b}', GC_LVT), - ('\u{ca4c}', '\u{ca4c}', GC_LV), ('\u{ca4d}', '\u{ca67}', GC_LVT), ('\u{ca68}', '\u{ca68}', - GC_LV), ('\u{ca69}', '\u{ca83}', GC_LVT), ('\u{ca84}', '\u{ca84}', GC_LV), ('\u{ca85}', - '\u{ca9f}', GC_LVT), ('\u{caa0}', '\u{caa0}', GC_LV), ('\u{caa1}', '\u{cabb}', GC_LVT), - ('\u{cabc}', '\u{cabc}', GC_LV), ('\u{cabd}', '\u{cad7}', GC_LVT), ('\u{cad8}', '\u{cad8}', - GC_LV), ('\u{cad9}', '\u{caf3}', GC_LVT), ('\u{caf4}', '\u{caf4}', GC_LV), ('\u{caf5}', - '\u{cb0f}', GC_LVT), ('\u{cb10}', '\u{cb10}', GC_LV), ('\u{cb11}', '\u{cb2b}', GC_LVT), - ('\u{cb2c}', '\u{cb2c}', GC_LV), ('\u{cb2d}', '\u{cb47}', GC_LVT), ('\u{cb48}', '\u{cb48}', - GC_LV), ('\u{cb49}', '\u{cb63}', GC_LVT), ('\u{cb64}', '\u{cb64}', GC_LV), ('\u{cb65}', - '\u{cb7f}', GC_LVT), ('\u{cb80}', '\u{cb80}', GC_LV), ('\u{cb81}', '\u{cb9b}', GC_LVT), - ('\u{cb9c}', '\u{cb9c}', GC_LV), ('\u{cb9d}', '\u{cbb7}', GC_LVT), ('\u{cbb8}', '\u{cbb8}', - GC_LV), ('\u{cbb9}', '\u{cbd3}', GC_LVT), ('\u{cbd4}', '\u{cbd4}', GC_LV), ('\u{cbd5}', - '\u{cbef}', GC_LVT), ('\u{cbf0}', '\u{cbf0}', GC_LV), ('\u{cbf1}', '\u{cc0b}', GC_LVT), - ('\u{cc0c}', '\u{cc0c}', GC_LV), ('\u{cc0d}', '\u{cc27}', GC_LVT), ('\u{cc28}', '\u{cc28}', - GC_LV), ('\u{cc29}', '\u{cc43}', GC_LVT), ('\u{cc44}', '\u{cc44}', GC_LV), ('\u{cc45}', - '\u{cc5f}', GC_LVT), ('\u{cc60}', '\u{cc60}', GC_LV), ('\u{cc61}', '\u{cc7b}', GC_LVT), - ('\u{cc7c}', '\u{cc7c}', GC_LV), ('\u{cc7d}', '\u{cc97}', GC_LVT), ('\u{cc98}', '\u{cc98}', - GC_LV), ('\u{cc99}', '\u{ccb3}', GC_LVT), ('\u{ccb4}', '\u{ccb4}', GC_LV), ('\u{ccb5}', - '\u{cccf}', GC_LVT), ('\u{ccd0}', '\u{ccd0}', GC_LV), ('\u{ccd1}', '\u{cceb}', GC_LVT), - ('\u{ccec}', '\u{ccec}', GC_LV), ('\u{cced}', '\u{cd07}', GC_LVT), ('\u{cd08}', '\u{cd08}', - GC_LV), ('\u{cd09}', '\u{cd23}', GC_LVT), ('\u{cd24}', '\u{cd24}', GC_LV), ('\u{cd25}', - '\u{cd3f}', GC_LVT), ('\u{cd40}', '\u{cd40}', GC_LV), ('\u{cd41}', '\u{cd5b}', GC_LVT), - ('\u{cd5c}', '\u{cd5c}', GC_LV), ('\u{cd5d}', '\u{cd77}', GC_LVT), ('\u{cd78}', '\u{cd78}', - GC_LV), ('\u{cd79}', '\u{cd93}', GC_LVT), ('\u{cd94}', '\u{cd94}', GC_LV), ('\u{cd95}', - '\u{cdaf}', GC_LVT), ('\u{cdb0}', '\u{cdb0}', GC_LV), ('\u{cdb1}', '\u{cdcb}', GC_LVT), - ('\u{cdcc}', '\u{cdcc}', GC_LV), ('\u{cdcd}', '\u{cde7}', GC_LVT), ('\u{cde8}', '\u{cde8}', - GC_LV), ('\u{cde9}', '\u{ce03}', GC_LVT), ('\u{ce04}', '\u{ce04}', GC_LV), ('\u{ce05}', - '\u{ce1f}', GC_LVT), ('\u{ce20}', '\u{ce20}', GC_LV), ('\u{ce21}', '\u{ce3b}', GC_LVT), - ('\u{ce3c}', '\u{ce3c}', GC_LV), ('\u{ce3d}', '\u{ce57}', GC_LVT), ('\u{ce58}', '\u{ce58}', - GC_LV), ('\u{ce59}', '\u{ce73}', GC_LVT), ('\u{ce74}', '\u{ce74}', GC_LV), ('\u{ce75}', - '\u{ce8f}', GC_LVT), ('\u{ce90}', '\u{ce90}', GC_LV), ('\u{ce91}', '\u{ceab}', GC_LVT), - ('\u{ceac}', '\u{ceac}', GC_LV), ('\u{cead}', '\u{cec7}', GC_LVT), ('\u{cec8}', '\u{cec8}', - GC_LV), ('\u{cec9}', '\u{cee3}', GC_LVT), ('\u{cee4}', '\u{cee4}', GC_LV), ('\u{cee5}', - '\u{ceff}', GC_LVT), ('\u{cf00}', '\u{cf00}', GC_LV), ('\u{cf01}', '\u{cf1b}', GC_LVT), - ('\u{cf1c}', '\u{cf1c}', GC_LV), ('\u{cf1d}', '\u{cf37}', GC_LVT), ('\u{cf38}', '\u{cf38}', - GC_LV), ('\u{cf39}', '\u{cf53}', GC_LVT), ('\u{cf54}', '\u{cf54}', GC_LV), ('\u{cf55}', - '\u{cf6f}', GC_LVT), ('\u{cf70}', '\u{cf70}', GC_LV), ('\u{cf71}', '\u{cf8b}', GC_LVT), - ('\u{cf8c}', '\u{cf8c}', GC_LV), ('\u{cf8d}', '\u{cfa7}', GC_LVT), ('\u{cfa8}', '\u{cfa8}', - GC_LV), ('\u{cfa9}', '\u{cfc3}', GC_LVT), ('\u{cfc4}', '\u{cfc4}', GC_LV), ('\u{cfc5}', - '\u{cfdf}', GC_LVT), ('\u{cfe0}', '\u{cfe0}', GC_LV), ('\u{cfe1}', '\u{cffb}', GC_LVT), - ('\u{cffc}', '\u{cffc}', GC_LV), ('\u{cffd}', '\u{d017}', GC_LVT), ('\u{d018}', '\u{d018}', - GC_LV), ('\u{d019}', '\u{d033}', GC_LVT), ('\u{d034}', '\u{d034}', GC_LV), ('\u{d035}', - '\u{d04f}', GC_LVT), ('\u{d050}', '\u{d050}', GC_LV), ('\u{d051}', '\u{d06b}', GC_LVT), - ('\u{d06c}', '\u{d06c}', GC_LV), ('\u{d06d}', '\u{d087}', GC_LVT), ('\u{d088}', '\u{d088}', - GC_LV), ('\u{d089}', '\u{d0a3}', GC_LVT), ('\u{d0a4}', '\u{d0a4}', GC_LV), ('\u{d0a5}', - '\u{d0bf}', GC_LVT), ('\u{d0c0}', '\u{d0c0}', GC_LV), ('\u{d0c1}', '\u{d0db}', GC_LVT), - ('\u{d0dc}', '\u{d0dc}', GC_LV), ('\u{d0dd}', '\u{d0f7}', GC_LVT), ('\u{d0f8}', '\u{d0f8}', - GC_LV), ('\u{d0f9}', '\u{d113}', GC_LVT), ('\u{d114}', '\u{d114}', GC_LV), ('\u{d115}', - '\u{d12f}', GC_LVT), ('\u{d130}', '\u{d130}', GC_LV), ('\u{d131}', '\u{d14b}', GC_LVT), - ('\u{d14c}', '\u{d14c}', GC_LV), ('\u{d14d}', '\u{d167}', GC_LVT), ('\u{d168}', '\u{d168}', - GC_LV), ('\u{d169}', '\u{d183}', GC_LVT), ('\u{d184}', '\u{d184}', GC_LV), ('\u{d185}', - '\u{d19f}', GC_LVT), ('\u{d1a0}', '\u{d1a0}', GC_LV), ('\u{d1a1}', '\u{d1bb}', GC_LVT), - ('\u{d1bc}', '\u{d1bc}', GC_LV), ('\u{d1bd}', '\u{d1d7}', GC_LVT), ('\u{d1d8}', '\u{d1d8}', - GC_LV), ('\u{d1d9}', '\u{d1f3}', GC_LVT), ('\u{d1f4}', '\u{d1f4}', GC_LV), ('\u{d1f5}', - '\u{d20f}', GC_LVT), ('\u{d210}', '\u{d210}', GC_LV), ('\u{d211}', '\u{d22b}', GC_LVT), - ('\u{d22c}', '\u{d22c}', GC_LV), ('\u{d22d}', '\u{d247}', GC_LVT), ('\u{d248}', '\u{d248}', - GC_LV), ('\u{d249}', '\u{d263}', GC_LVT), ('\u{d264}', '\u{d264}', GC_LV), ('\u{d265}', - '\u{d27f}', GC_LVT), ('\u{d280}', '\u{d280}', GC_LV), ('\u{d281}', '\u{d29b}', GC_LVT), - ('\u{d29c}', '\u{d29c}', GC_LV), ('\u{d29d}', '\u{d2b7}', GC_LVT), ('\u{d2b8}', '\u{d2b8}', - GC_LV), ('\u{d2b9}', '\u{d2d3}', GC_LVT), ('\u{d2d4}', '\u{d2d4}', GC_LV), ('\u{d2d5}', - '\u{d2ef}', GC_LVT), ('\u{d2f0}', '\u{d2f0}', GC_LV), ('\u{d2f1}', '\u{d30b}', GC_LVT), - ('\u{d30c}', '\u{d30c}', GC_LV), ('\u{d30d}', '\u{d327}', GC_LVT), ('\u{d328}', '\u{d328}', - GC_LV), ('\u{d329}', '\u{d343}', GC_LVT), ('\u{d344}', '\u{d344}', GC_LV), ('\u{d345}', - '\u{d35f}', GC_LVT), ('\u{d360}', '\u{d360}', GC_LV), ('\u{d361}', '\u{d37b}', GC_LVT), - ('\u{d37c}', '\u{d37c}', GC_LV), ('\u{d37d}', '\u{d397}', GC_LVT), ('\u{d398}', '\u{d398}', - GC_LV), ('\u{d399}', '\u{d3b3}', GC_LVT), ('\u{d3b4}', '\u{d3b4}', GC_LV), ('\u{d3b5}', - '\u{d3cf}', GC_LVT), ('\u{d3d0}', '\u{d3d0}', GC_LV), ('\u{d3d1}', '\u{d3eb}', GC_LVT), - ('\u{d3ec}', '\u{d3ec}', GC_LV), ('\u{d3ed}', '\u{d407}', GC_LVT), ('\u{d408}', '\u{d408}', - GC_LV), ('\u{d409}', '\u{d423}', GC_LVT), ('\u{d424}', '\u{d424}', GC_LV), ('\u{d425}', - '\u{d43f}', GC_LVT), ('\u{d440}', '\u{d440}', GC_LV), ('\u{d441}', '\u{d45b}', GC_LVT), - ('\u{d45c}', '\u{d45c}', GC_LV), ('\u{d45d}', '\u{d477}', GC_LVT), ('\u{d478}', '\u{d478}', - GC_LV), ('\u{d479}', '\u{d493}', GC_LVT), ('\u{d494}', '\u{d494}', GC_LV), ('\u{d495}', - '\u{d4af}', GC_LVT), ('\u{d4b0}', '\u{d4b0}', GC_LV), ('\u{d4b1}', '\u{d4cb}', GC_LVT), - ('\u{d4cc}', '\u{d4cc}', GC_LV), ('\u{d4cd}', '\u{d4e7}', GC_LVT), ('\u{d4e8}', '\u{d4e8}', - GC_LV), ('\u{d4e9}', '\u{d503}', GC_LVT), ('\u{d504}', '\u{d504}', GC_LV), ('\u{d505}', - '\u{d51f}', GC_LVT), ('\u{d520}', '\u{d520}', GC_LV), ('\u{d521}', '\u{d53b}', GC_LVT), - ('\u{d53c}', '\u{d53c}', GC_LV), ('\u{d53d}', '\u{d557}', GC_LVT), ('\u{d558}', '\u{d558}', - GC_LV), ('\u{d559}', '\u{d573}', GC_LVT), ('\u{d574}', '\u{d574}', GC_LV), ('\u{d575}', - '\u{d58f}', GC_LVT), ('\u{d590}', '\u{d590}', GC_LV), ('\u{d591}', '\u{d5ab}', GC_LVT), - ('\u{d5ac}', '\u{d5ac}', GC_LV), ('\u{d5ad}', '\u{d5c7}', GC_LVT), ('\u{d5c8}', '\u{d5c8}', - GC_LV), ('\u{d5c9}', '\u{d5e3}', GC_LVT), ('\u{d5e4}', '\u{d5e4}', GC_LV), ('\u{d5e5}', - '\u{d5ff}', GC_LVT), ('\u{d600}', '\u{d600}', GC_LV), ('\u{d601}', '\u{d61b}', GC_LVT), - ('\u{d61c}', '\u{d61c}', GC_LV), ('\u{d61d}', '\u{d637}', GC_LVT), ('\u{d638}', '\u{d638}', - GC_LV), ('\u{d639}', '\u{d653}', GC_LVT), ('\u{d654}', '\u{d654}', GC_LV), ('\u{d655}', - '\u{d66f}', GC_LVT), ('\u{d670}', '\u{d670}', GC_LV), ('\u{d671}', '\u{d68b}', GC_LVT), - ('\u{d68c}', '\u{d68c}', GC_LV), ('\u{d68d}', '\u{d6a7}', GC_LVT), ('\u{d6a8}', '\u{d6a8}', - GC_LV), ('\u{d6a9}', '\u{d6c3}', GC_LVT), ('\u{d6c4}', '\u{d6c4}', GC_LV), ('\u{d6c5}', - '\u{d6df}', GC_LVT), ('\u{d6e0}', '\u{d6e0}', GC_LV), ('\u{d6e1}', '\u{d6fb}', GC_LVT), - ('\u{d6fc}', '\u{d6fc}', GC_LV), ('\u{d6fd}', '\u{d717}', GC_LVT), ('\u{d718}', '\u{d718}', - GC_LV), ('\u{d719}', '\u{d733}', GC_LVT), ('\u{d734}', '\u{d734}', GC_LV), ('\u{d735}', - '\u{d74f}', GC_LVT), ('\u{d750}', '\u{d750}', GC_LV), ('\u{d751}', '\u{d76b}', GC_LVT), - ('\u{d76c}', '\u{d76c}', GC_LV), ('\u{d76d}', '\u{d787}', GC_LVT), ('\u{d788}', '\u{d788}', - GC_LV), ('\u{d789}', '\u{d7a3}', GC_LVT), ('\u{d7b0}', '\u{d7c6}', GC_V), ('\u{d7cb}', - '\u{d7fb}', GC_T), ('\u{fb1e}', '\u{fb1e}', GC_Extend), ('\u{fe00}', '\u{fe0f}', GC_Extend), + ('\u{fc6}', '\u{fc6}', GC_Extend), ('\u{102d}', '\u{1030}', GC_Extend), ('\u{1031}', + '\u{1031}', GC_SpacingMark), ('\u{1032}', '\u{1037}', GC_Extend), ('\u{1039}', '\u{103a}', + GC_Extend), ('\u{103b}', '\u{103c}', GC_SpacingMark), ('\u{103d}', '\u{103e}', GC_Extend), + ('\u{1056}', '\u{1057}', GC_SpacingMark), ('\u{1058}', '\u{1059}', GC_Extend), ('\u{105e}', + '\u{1060}', GC_Extend), ('\u{1071}', '\u{1074}', GC_Extend), ('\u{1082}', '\u{1082}', + GC_Extend), ('\u{1084}', '\u{1084}', GC_SpacingMark), ('\u{1085}', '\u{1086}', GC_Extend), + ('\u{108d}', '\u{108d}', GC_Extend), ('\u{109d}', '\u{109d}', GC_Extend), ('\u{1100}', + '\u{115f}', GC_L), ('\u{1160}', '\u{11a7}', GC_V), ('\u{11a8}', '\u{11ff}', GC_T), + ('\u{135d}', '\u{135f}', GC_Extend), ('\u{1712}', '\u{1714}', GC_Extend), ('\u{1732}', + '\u{1734}', GC_Extend), ('\u{1752}', '\u{1753}', GC_Extend), ('\u{1772}', '\u{1773}', + GC_Extend), ('\u{17b4}', '\u{17b5}', GC_Extend), ('\u{17b6}', '\u{17b6}', GC_SpacingMark), + ('\u{17b7}', '\u{17bd}', GC_Extend), ('\u{17be}', '\u{17c5}', GC_SpacingMark), ('\u{17c6}', + '\u{17c6}', GC_Extend), ('\u{17c7}', '\u{17c8}', GC_SpacingMark), ('\u{17c9}', '\u{17d3}', + GC_Extend), ('\u{17dd}', '\u{17dd}', GC_Extend), ('\u{180b}', '\u{180d}', GC_Extend), + ('\u{180e}', '\u{180e}', GC_Control), ('\u{18a9}', '\u{18a9}', GC_Extend), ('\u{1920}', + '\u{1922}', GC_Extend), ('\u{1923}', '\u{1926}', GC_SpacingMark), ('\u{1927}', '\u{1928}', + GC_Extend), ('\u{1929}', '\u{192b}', GC_SpacingMark), ('\u{1930}', '\u{1931}', + GC_SpacingMark), ('\u{1932}', '\u{1932}', GC_Extend), ('\u{1933}', '\u{1938}', + GC_SpacingMark), ('\u{1939}', '\u{193b}', GC_Extend), ('\u{19b5}', '\u{19b7}', + GC_SpacingMark), ('\u{19ba}', '\u{19ba}', GC_SpacingMark), ('\u{1a17}', '\u{1a18}', + GC_Extend), ('\u{1a19}', '\u{1a1a}', GC_SpacingMark), ('\u{1a1b}', '\u{1a1b}', GC_Extend), + ('\u{1a55}', '\u{1a55}', GC_SpacingMark), ('\u{1a56}', '\u{1a56}', GC_Extend), ('\u{1a57}', + '\u{1a57}', GC_SpacingMark), ('\u{1a58}', '\u{1a5e}', GC_Extend), ('\u{1a60}', '\u{1a60}', + GC_Extend), ('\u{1a62}', '\u{1a62}', GC_Extend), ('\u{1a65}', '\u{1a6c}', GC_Extend), + ('\u{1a6d}', '\u{1a72}', GC_SpacingMark), ('\u{1a73}', '\u{1a7c}', GC_Extend), ('\u{1a7f}', + '\u{1a7f}', GC_Extend), ('\u{1ab0}', '\u{1abd}', GC_Extend), ('\u{1abe}', '\u{1abe}', + GC_Extend), ('\u{1b00}', '\u{1b03}', GC_Extend), ('\u{1b04}', '\u{1b04}', GC_SpacingMark), + ('\u{1b34}', '\u{1b34}', GC_Extend), ('\u{1b35}', '\u{1b35}', GC_SpacingMark), ('\u{1b36}', + '\u{1b3a}', GC_Extend), ('\u{1b3b}', '\u{1b3b}', GC_SpacingMark), ('\u{1b3c}', '\u{1b3c}', + GC_Extend), ('\u{1b3d}', '\u{1b41}', GC_SpacingMark), ('\u{1b42}', '\u{1b42}', GC_Extend), + ('\u{1b43}', '\u{1b44}', GC_SpacingMark), ('\u{1b6b}', '\u{1b73}', GC_Extend), ('\u{1b80}', + '\u{1b81}', GC_Extend), ('\u{1b82}', '\u{1b82}', GC_SpacingMark), ('\u{1ba1}', '\u{1ba1}', + GC_SpacingMark), ('\u{1ba2}', '\u{1ba5}', GC_Extend), ('\u{1ba6}', '\u{1ba7}', + GC_SpacingMark), ('\u{1ba8}', '\u{1ba9}', GC_Extend), ('\u{1baa}', '\u{1baa}', + GC_SpacingMark), ('\u{1bab}', '\u{1bad}', GC_Extend), ('\u{1be6}', '\u{1be6}', GC_Extend), + ('\u{1be7}', '\u{1be7}', GC_SpacingMark), ('\u{1be8}', '\u{1be9}', GC_Extend), ('\u{1bea}', + '\u{1bec}', GC_SpacingMark), ('\u{1bed}', '\u{1bed}', GC_Extend), ('\u{1bee}', '\u{1bee}', + GC_SpacingMark), ('\u{1bef}', '\u{1bf1}', GC_Extend), ('\u{1bf2}', '\u{1bf3}', + GC_SpacingMark), ('\u{1c24}', '\u{1c2b}', GC_SpacingMark), ('\u{1c2c}', '\u{1c33}', + GC_Extend), ('\u{1c34}', '\u{1c35}', GC_SpacingMark), ('\u{1c36}', '\u{1c37}', GC_Extend), + ('\u{1cd0}', '\u{1cd2}', GC_Extend), ('\u{1cd4}', '\u{1ce0}', GC_Extend), ('\u{1ce1}', + '\u{1ce1}', GC_SpacingMark), ('\u{1ce2}', '\u{1ce8}', GC_Extend), ('\u{1ced}', '\u{1ced}', + GC_Extend), ('\u{1cf2}', '\u{1cf3}', GC_SpacingMark), ('\u{1cf4}', '\u{1cf4}', GC_Extend), + ('\u{1cf8}', '\u{1cf9}', GC_Extend), ('\u{1dc0}', '\u{1df5}', GC_Extend), ('\u{1dfc}', + '\u{1dff}', GC_Extend), ('\u{200b}', '\u{200b}', GC_Control), ('\u{200c}', '\u{200d}', + GC_Extend), ('\u{200e}', '\u{200f}', GC_Control), ('\u{2028}', '\u{202e}', GC_Control), + ('\u{2060}', '\u{206f}', GC_Control), ('\u{20d0}', '\u{20dc}', GC_Extend), ('\u{20dd}', + '\u{20e0}', GC_Extend), ('\u{20e1}', '\u{20e1}', GC_Extend), ('\u{20e2}', '\u{20e4}', + GC_Extend), ('\u{20e5}', '\u{20f0}', GC_Extend), ('\u{2cef}', '\u{2cf1}', GC_Extend), + ('\u{2d7f}', '\u{2d7f}', GC_Extend), ('\u{2de0}', '\u{2dff}', GC_Extend), ('\u{302a}', + '\u{302d}', GC_Extend), ('\u{302e}', '\u{302f}', GC_Extend), ('\u{3099}', '\u{309a}', + GC_Extend), ('\u{a66f}', '\u{a66f}', GC_Extend), ('\u{a670}', '\u{a672}', GC_Extend), + ('\u{a674}', '\u{a67d}', GC_Extend), ('\u{a69f}', '\u{a69f}', GC_Extend), ('\u{a6f0}', + '\u{a6f1}', GC_Extend), ('\u{a802}', '\u{a802}', GC_Extend), ('\u{a806}', '\u{a806}', + GC_Extend), ('\u{a80b}', '\u{a80b}', GC_Extend), ('\u{a823}', '\u{a824}', GC_SpacingMark), + ('\u{a825}', '\u{a826}', GC_Extend), ('\u{a827}', '\u{a827}', GC_SpacingMark), ('\u{a880}', + '\u{a881}', GC_SpacingMark), ('\u{a8b4}', '\u{a8c3}', GC_SpacingMark), ('\u{a8c4}', + '\u{a8c4}', GC_Extend), ('\u{a8e0}', '\u{a8f1}', GC_Extend), ('\u{a926}', '\u{a92d}', + GC_Extend), ('\u{a947}', '\u{a951}', GC_Extend), ('\u{a952}', '\u{a953}', GC_SpacingMark), + ('\u{a960}', '\u{a97c}', GC_L), ('\u{a980}', '\u{a982}', GC_Extend), ('\u{a983}', + '\u{a983}', GC_SpacingMark), ('\u{a9b3}', '\u{a9b3}', GC_Extend), ('\u{a9b4}', '\u{a9b5}', + GC_SpacingMark), ('\u{a9b6}', '\u{a9b9}', GC_Extend), ('\u{a9ba}', '\u{a9bb}', + GC_SpacingMark), ('\u{a9bc}', '\u{a9bc}', GC_Extend), ('\u{a9bd}', '\u{a9c0}', + GC_SpacingMark), ('\u{a9e5}', '\u{a9e5}', GC_Extend), ('\u{aa29}', '\u{aa2e}', GC_Extend), + ('\u{aa2f}', '\u{aa30}', GC_SpacingMark), ('\u{aa31}', '\u{aa32}', GC_Extend), ('\u{aa33}', + '\u{aa34}', GC_SpacingMark), ('\u{aa35}', '\u{aa36}', GC_Extend), ('\u{aa43}', '\u{aa43}', + GC_Extend), ('\u{aa4c}', '\u{aa4c}', GC_Extend), ('\u{aa4d}', '\u{aa4d}', GC_SpacingMark), + ('\u{aa7c}', '\u{aa7c}', GC_Extend), ('\u{aab0}', '\u{aab0}', GC_Extend), ('\u{aab2}', + '\u{aab4}', GC_Extend), ('\u{aab7}', '\u{aab8}', GC_Extend), ('\u{aabe}', '\u{aabf}', + GC_Extend), ('\u{aac1}', '\u{aac1}', GC_Extend), ('\u{aaeb}', '\u{aaeb}', GC_SpacingMark), + ('\u{aaec}', '\u{aaed}', GC_Extend), ('\u{aaee}', '\u{aaef}', GC_SpacingMark), ('\u{aaf5}', + '\u{aaf5}', GC_SpacingMark), ('\u{aaf6}', '\u{aaf6}', GC_Extend), ('\u{abe3}', '\u{abe4}', + GC_SpacingMark), ('\u{abe5}', '\u{abe5}', GC_Extend), ('\u{abe6}', '\u{abe7}', + GC_SpacingMark), ('\u{abe8}', '\u{abe8}', GC_Extend), ('\u{abe9}', '\u{abea}', + GC_SpacingMark), ('\u{abec}', '\u{abec}', GC_SpacingMark), ('\u{abed}', '\u{abed}', + GC_Extend), ('\u{ac00}', '\u{ac00}', GC_LV), ('\u{ac01}', '\u{ac1b}', GC_LVT), ('\u{ac1c}', + '\u{ac1c}', GC_LV), ('\u{ac1d}', '\u{ac37}', GC_LVT), ('\u{ac38}', '\u{ac38}', GC_LV), + ('\u{ac39}', '\u{ac53}', GC_LVT), ('\u{ac54}', '\u{ac54}', GC_LV), ('\u{ac55}', '\u{ac6f}', + GC_LVT), ('\u{ac70}', '\u{ac70}', GC_LV), ('\u{ac71}', '\u{ac8b}', GC_LVT), ('\u{ac8c}', + '\u{ac8c}', GC_LV), ('\u{ac8d}', '\u{aca7}', GC_LVT), ('\u{aca8}', '\u{aca8}', GC_LV), + ('\u{aca9}', '\u{acc3}', GC_LVT), ('\u{acc4}', '\u{acc4}', GC_LV), ('\u{acc5}', '\u{acdf}', + GC_LVT), ('\u{ace0}', '\u{ace0}', GC_LV), ('\u{ace1}', '\u{acfb}', GC_LVT), ('\u{acfc}', + '\u{acfc}', GC_LV), ('\u{acfd}', '\u{ad17}', GC_LVT), ('\u{ad18}', '\u{ad18}', GC_LV), + ('\u{ad19}', '\u{ad33}', GC_LVT), ('\u{ad34}', '\u{ad34}', GC_LV), ('\u{ad35}', '\u{ad4f}', + GC_LVT), ('\u{ad50}', '\u{ad50}', GC_LV), ('\u{ad51}', '\u{ad6b}', GC_LVT), ('\u{ad6c}', + '\u{ad6c}', GC_LV), ('\u{ad6d}', '\u{ad87}', GC_LVT), ('\u{ad88}', '\u{ad88}', GC_LV), + ('\u{ad89}', '\u{ada3}', GC_LVT), ('\u{ada4}', '\u{ada4}', GC_LV), ('\u{ada5}', '\u{adbf}', + GC_LVT), ('\u{adc0}', '\u{adc0}', GC_LV), ('\u{adc1}', '\u{addb}', GC_LVT), ('\u{addc}', + '\u{addc}', GC_LV), ('\u{addd}', '\u{adf7}', GC_LVT), ('\u{adf8}', '\u{adf8}', GC_LV), + ('\u{adf9}', '\u{ae13}', GC_LVT), ('\u{ae14}', '\u{ae14}', GC_LV), ('\u{ae15}', '\u{ae2f}', + GC_LVT), ('\u{ae30}', '\u{ae30}', GC_LV), ('\u{ae31}', '\u{ae4b}', GC_LVT), ('\u{ae4c}', + '\u{ae4c}', GC_LV), ('\u{ae4d}', '\u{ae67}', GC_LVT), ('\u{ae68}', '\u{ae68}', GC_LV), + ('\u{ae69}', '\u{ae83}', GC_LVT), ('\u{ae84}', '\u{ae84}', GC_LV), ('\u{ae85}', '\u{ae9f}', + GC_LVT), ('\u{aea0}', '\u{aea0}', GC_LV), ('\u{aea1}', '\u{aebb}', GC_LVT), ('\u{aebc}', + '\u{aebc}', GC_LV), ('\u{aebd}', '\u{aed7}', GC_LVT), ('\u{aed8}', '\u{aed8}', GC_LV), + ('\u{aed9}', '\u{aef3}', GC_LVT), ('\u{aef4}', '\u{aef4}', GC_LV), ('\u{aef5}', '\u{af0f}', + GC_LVT), ('\u{af10}', '\u{af10}', GC_LV), ('\u{af11}', '\u{af2b}', GC_LVT), ('\u{af2c}', + '\u{af2c}', GC_LV), ('\u{af2d}', '\u{af47}', GC_LVT), ('\u{af48}', '\u{af48}', GC_LV), + ('\u{af49}', '\u{af63}', GC_LVT), ('\u{af64}', '\u{af64}', GC_LV), ('\u{af65}', '\u{af7f}', + GC_LVT), ('\u{af80}', '\u{af80}', GC_LV), ('\u{af81}', '\u{af9b}', GC_LVT), ('\u{af9c}', + '\u{af9c}', GC_LV), ('\u{af9d}', '\u{afb7}', GC_LVT), ('\u{afb8}', '\u{afb8}', GC_LV), + ('\u{afb9}', '\u{afd3}', GC_LVT), ('\u{afd4}', '\u{afd4}', GC_LV), ('\u{afd5}', '\u{afef}', + GC_LVT), ('\u{aff0}', '\u{aff0}', GC_LV), ('\u{aff1}', '\u{b00b}', GC_LVT), ('\u{b00c}', + '\u{b00c}', GC_LV), ('\u{b00d}', '\u{b027}', GC_LVT), ('\u{b028}', '\u{b028}', GC_LV), + ('\u{b029}', '\u{b043}', GC_LVT), ('\u{b044}', '\u{b044}', GC_LV), ('\u{b045}', '\u{b05f}', + GC_LVT), ('\u{b060}', '\u{b060}', GC_LV), ('\u{b061}', '\u{b07b}', GC_LVT), ('\u{b07c}', + '\u{b07c}', GC_LV), ('\u{b07d}', '\u{b097}', GC_LVT), ('\u{b098}', '\u{b098}', GC_LV), + ('\u{b099}', '\u{b0b3}', GC_LVT), ('\u{b0b4}', '\u{b0b4}', GC_LV), ('\u{b0b5}', '\u{b0cf}', + GC_LVT), ('\u{b0d0}', '\u{b0d0}', GC_LV), ('\u{b0d1}', '\u{b0eb}', GC_LVT), ('\u{b0ec}', + '\u{b0ec}', GC_LV), ('\u{b0ed}', '\u{b107}', GC_LVT), ('\u{b108}', '\u{b108}', GC_LV), + ('\u{b109}', '\u{b123}', GC_LVT), ('\u{b124}', '\u{b124}', GC_LV), ('\u{b125}', '\u{b13f}', + GC_LVT), ('\u{b140}', '\u{b140}', GC_LV), ('\u{b141}', '\u{b15b}', GC_LVT), ('\u{b15c}', + '\u{b15c}', GC_LV), ('\u{b15d}', '\u{b177}', GC_LVT), ('\u{b178}', '\u{b178}', GC_LV), + ('\u{b179}', '\u{b193}', GC_LVT), ('\u{b194}', '\u{b194}', GC_LV), ('\u{b195}', '\u{b1af}', + GC_LVT), ('\u{b1b0}', '\u{b1b0}', GC_LV), ('\u{b1b1}', '\u{b1cb}', GC_LVT), ('\u{b1cc}', + '\u{b1cc}', GC_LV), ('\u{b1cd}', '\u{b1e7}', GC_LVT), ('\u{b1e8}', '\u{b1e8}', GC_LV), + ('\u{b1e9}', '\u{b203}', GC_LVT), ('\u{b204}', '\u{b204}', GC_LV), ('\u{b205}', '\u{b21f}', + GC_LVT), ('\u{b220}', '\u{b220}', GC_LV), ('\u{b221}', '\u{b23b}', GC_LVT), ('\u{b23c}', + '\u{b23c}', GC_LV), ('\u{b23d}', '\u{b257}', GC_LVT), ('\u{b258}', '\u{b258}', GC_LV), + ('\u{b259}', '\u{b273}', GC_LVT), ('\u{b274}', '\u{b274}', GC_LV), ('\u{b275}', '\u{b28f}', + GC_LVT), ('\u{b290}', '\u{b290}', GC_LV), ('\u{b291}', '\u{b2ab}', GC_LVT), ('\u{b2ac}', + '\u{b2ac}', GC_LV), ('\u{b2ad}', '\u{b2c7}', GC_LVT), ('\u{b2c8}', '\u{b2c8}', GC_LV), + ('\u{b2c9}', '\u{b2e3}', GC_LVT), ('\u{b2e4}', '\u{b2e4}', GC_LV), ('\u{b2e5}', '\u{b2ff}', + GC_LVT), ('\u{b300}', '\u{b300}', GC_LV), ('\u{b301}', '\u{b31b}', GC_LVT), ('\u{b31c}', + '\u{b31c}', GC_LV), ('\u{b31d}', '\u{b337}', GC_LVT), ('\u{b338}', '\u{b338}', GC_LV), + ('\u{b339}', '\u{b353}', GC_LVT), ('\u{b354}', '\u{b354}', GC_LV), ('\u{b355}', '\u{b36f}', + GC_LVT), ('\u{b370}', '\u{b370}', GC_LV), ('\u{b371}', '\u{b38b}', GC_LVT), ('\u{b38c}', + '\u{b38c}', GC_LV), ('\u{b38d}', '\u{b3a7}', GC_LVT), ('\u{b3a8}', '\u{b3a8}', GC_LV), + ('\u{b3a9}', '\u{b3c3}', GC_LVT), ('\u{b3c4}', '\u{b3c4}', GC_LV), ('\u{b3c5}', '\u{b3df}', + GC_LVT), ('\u{b3e0}', '\u{b3e0}', GC_LV), ('\u{b3e1}', '\u{b3fb}', GC_LVT), ('\u{b3fc}', + '\u{b3fc}', GC_LV), ('\u{b3fd}', '\u{b417}', GC_LVT), ('\u{b418}', '\u{b418}', GC_LV), + ('\u{b419}', '\u{b433}', GC_LVT), ('\u{b434}', '\u{b434}', GC_LV), ('\u{b435}', '\u{b44f}', + GC_LVT), ('\u{b450}', '\u{b450}', GC_LV), ('\u{b451}', '\u{b46b}', GC_LVT), ('\u{b46c}', + '\u{b46c}', GC_LV), ('\u{b46d}', '\u{b487}', GC_LVT), ('\u{b488}', '\u{b488}', GC_LV), + ('\u{b489}', '\u{b4a3}', GC_LVT), ('\u{b4a4}', '\u{b4a4}', GC_LV), ('\u{b4a5}', '\u{b4bf}', + GC_LVT), ('\u{b4c0}', '\u{b4c0}', GC_LV), ('\u{b4c1}', '\u{b4db}', GC_LVT), ('\u{b4dc}', + '\u{b4dc}', GC_LV), ('\u{b4dd}', '\u{b4f7}', GC_LVT), ('\u{b4f8}', '\u{b4f8}', GC_LV), + ('\u{b4f9}', '\u{b513}', GC_LVT), ('\u{b514}', '\u{b514}', GC_LV), ('\u{b515}', '\u{b52f}', + GC_LVT), ('\u{b530}', '\u{b530}', GC_LV), ('\u{b531}', '\u{b54b}', GC_LVT), ('\u{b54c}', + '\u{b54c}', GC_LV), ('\u{b54d}', '\u{b567}', GC_LVT), ('\u{b568}', '\u{b568}', GC_LV), + ('\u{b569}', '\u{b583}', GC_LVT), ('\u{b584}', '\u{b584}', GC_LV), ('\u{b585}', '\u{b59f}', + GC_LVT), ('\u{b5a0}', '\u{b5a0}', GC_LV), ('\u{b5a1}', '\u{b5bb}', GC_LVT), ('\u{b5bc}', + '\u{b5bc}', GC_LV), ('\u{b5bd}', '\u{b5d7}', GC_LVT), ('\u{b5d8}', '\u{b5d8}', GC_LV), + ('\u{b5d9}', '\u{b5f3}', GC_LVT), ('\u{b5f4}', '\u{b5f4}', GC_LV), ('\u{b5f5}', '\u{b60f}', + GC_LVT), ('\u{b610}', '\u{b610}', GC_LV), ('\u{b611}', '\u{b62b}', GC_LVT), ('\u{b62c}', + '\u{b62c}', GC_LV), ('\u{b62d}', '\u{b647}', GC_LVT), ('\u{b648}', '\u{b648}', GC_LV), + ('\u{b649}', '\u{b663}', GC_LVT), ('\u{b664}', '\u{b664}', GC_LV), ('\u{b665}', '\u{b67f}', + GC_LVT), ('\u{b680}', '\u{b680}', GC_LV), ('\u{b681}', '\u{b69b}', GC_LVT), ('\u{b69c}', + '\u{b69c}', GC_LV), ('\u{b69d}', '\u{b6b7}', GC_LVT), ('\u{b6b8}', '\u{b6b8}', GC_LV), + ('\u{b6b9}', '\u{b6d3}', GC_LVT), ('\u{b6d4}', '\u{b6d4}', GC_LV), ('\u{b6d5}', '\u{b6ef}', + GC_LVT), ('\u{b6f0}', '\u{b6f0}', GC_LV), ('\u{b6f1}', '\u{b70b}', GC_LVT), ('\u{b70c}', + '\u{b70c}', GC_LV), ('\u{b70d}', '\u{b727}', GC_LVT), ('\u{b728}', '\u{b728}', GC_LV), + ('\u{b729}', '\u{b743}', GC_LVT), ('\u{b744}', '\u{b744}', GC_LV), ('\u{b745}', '\u{b75f}', + GC_LVT), ('\u{b760}', '\u{b760}', GC_LV), ('\u{b761}', '\u{b77b}', GC_LVT), ('\u{b77c}', + '\u{b77c}', GC_LV), ('\u{b77d}', '\u{b797}', GC_LVT), ('\u{b798}', '\u{b798}', GC_LV), + ('\u{b799}', '\u{b7b3}', GC_LVT), ('\u{b7b4}', '\u{b7b4}', GC_LV), ('\u{b7b5}', '\u{b7cf}', + GC_LVT), ('\u{b7d0}', '\u{b7d0}', GC_LV), ('\u{b7d1}', '\u{b7eb}', GC_LVT), ('\u{b7ec}', + '\u{b7ec}', GC_LV), ('\u{b7ed}', '\u{b807}', GC_LVT), ('\u{b808}', '\u{b808}', GC_LV), + ('\u{b809}', '\u{b823}', GC_LVT), ('\u{b824}', '\u{b824}', GC_LV), ('\u{b825}', '\u{b83f}', + GC_LVT), ('\u{b840}', '\u{b840}', GC_LV), ('\u{b841}', '\u{b85b}', GC_LVT), ('\u{b85c}', + '\u{b85c}', GC_LV), ('\u{b85d}', '\u{b877}', GC_LVT), ('\u{b878}', '\u{b878}', GC_LV), + ('\u{b879}', '\u{b893}', GC_LVT), ('\u{b894}', '\u{b894}', GC_LV), ('\u{b895}', '\u{b8af}', + GC_LVT), ('\u{b8b0}', '\u{b8b0}', GC_LV), ('\u{b8b1}', '\u{b8cb}', GC_LVT), ('\u{b8cc}', + '\u{b8cc}', GC_LV), ('\u{b8cd}', '\u{b8e7}', GC_LVT), ('\u{b8e8}', '\u{b8e8}', GC_LV), + ('\u{b8e9}', '\u{b903}', GC_LVT), ('\u{b904}', '\u{b904}', GC_LV), ('\u{b905}', '\u{b91f}', + GC_LVT), ('\u{b920}', '\u{b920}', GC_LV), ('\u{b921}', '\u{b93b}', GC_LVT), ('\u{b93c}', + '\u{b93c}', GC_LV), ('\u{b93d}', '\u{b957}', GC_LVT), ('\u{b958}', '\u{b958}', GC_LV), + ('\u{b959}', '\u{b973}', GC_LVT), ('\u{b974}', '\u{b974}', GC_LV), ('\u{b975}', '\u{b98f}', + GC_LVT), ('\u{b990}', '\u{b990}', GC_LV), ('\u{b991}', '\u{b9ab}', GC_LVT), ('\u{b9ac}', + '\u{b9ac}', GC_LV), ('\u{b9ad}', '\u{b9c7}', GC_LVT), ('\u{b9c8}', '\u{b9c8}', GC_LV), + ('\u{b9c9}', '\u{b9e3}', GC_LVT), ('\u{b9e4}', '\u{b9e4}', GC_LV), ('\u{b9e5}', '\u{b9ff}', + GC_LVT), ('\u{ba00}', '\u{ba00}', GC_LV), ('\u{ba01}', '\u{ba1b}', GC_LVT), ('\u{ba1c}', + '\u{ba1c}', GC_LV), ('\u{ba1d}', '\u{ba37}', GC_LVT), ('\u{ba38}', '\u{ba38}', GC_LV), + ('\u{ba39}', '\u{ba53}', GC_LVT), ('\u{ba54}', '\u{ba54}', GC_LV), ('\u{ba55}', '\u{ba6f}', + GC_LVT), ('\u{ba70}', '\u{ba70}', GC_LV), ('\u{ba71}', '\u{ba8b}', GC_LVT), ('\u{ba8c}', + '\u{ba8c}', GC_LV), ('\u{ba8d}', '\u{baa7}', GC_LVT), ('\u{baa8}', '\u{baa8}', GC_LV), + ('\u{baa9}', '\u{bac3}', GC_LVT), ('\u{bac4}', '\u{bac4}', GC_LV), ('\u{bac5}', '\u{badf}', + GC_LVT), ('\u{bae0}', '\u{bae0}', GC_LV), ('\u{bae1}', '\u{bafb}', GC_LVT), ('\u{bafc}', + '\u{bafc}', GC_LV), ('\u{bafd}', '\u{bb17}', GC_LVT), ('\u{bb18}', '\u{bb18}', GC_LV), + ('\u{bb19}', '\u{bb33}', GC_LVT), ('\u{bb34}', '\u{bb34}', GC_LV), ('\u{bb35}', '\u{bb4f}', + GC_LVT), ('\u{bb50}', '\u{bb50}', GC_LV), ('\u{bb51}', '\u{bb6b}', GC_LVT), ('\u{bb6c}', + '\u{bb6c}', GC_LV), ('\u{bb6d}', '\u{bb87}', GC_LVT), ('\u{bb88}', '\u{bb88}', GC_LV), + ('\u{bb89}', '\u{bba3}', GC_LVT), ('\u{bba4}', '\u{bba4}', GC_LV), ('\u{bba5}', '\u{bbbf}', + GC_LVT), ('\u{bbc0}', '\u{bbc0}', GC_LV), ('\u{bbc1}', '\u{bbdb}', GC_LVT), ('\u{bbdc}', + '\u{bbdc}', GC_LV), ('\u{bbdd}', '\u{bbf7}', GC_LVT), ('\u{bbf8}', '\u{bbf8}', GC_LV), + ('\u{bbf9}', '\u{bc13}', GC_LVT), ('\u{bc14}', '\u{bc14}', GC_LV), ('\u{bc15}', '\u{bc2f}', + GC_LVT), ('\u{bc30}', '\u{bc30}', GC_LV), ('\u{bc31}', '\u{bc4b}', GC_LVT), ('\u{bc4c}', + '\u{bc4c}', GC_LV), ('\u{bc4d}', '\u{bc67}', GC_LVT), ('\u{bc68}', '\u{bc68}', GC_LV), + ('\u{bc69}', '\u{bc83}', GC_LVT), ('\u{bc84}', '\u{bc84}', GC_LV), ('\u{bc85}', '\u{bc9f}', + GC_LVT), ('\u{bca0}', '\u{bca0}', GC_LV), ('\u{bca1}', '\u{bcbb}', GC_LVT), ('\u{bcbc}', + '\u{bcbc}', GC_LV), ('\u{bcbd}', '\u{bcd7}', GC_LVT), ('\u{bcd8}', '\u{bcd8}', GC_LV), + ('\u{bcd9}', '\u{bcf3}', GC_LVT), ('\u{bcf4}', '\u{bcf4}', GC_LV), ('\u{bcf5}', '\u{bd0f}', + GC_LVT), ('\u{bd10}', '\u{bd10}', GC_LV), ('\u{bd11}', '\u{bd2b}', GC_LVT), ('\u{bd2c}', + '\u{bd2c}', GC_LV), ('\u{bd2d}', '\u{bd47}', GC_LVT), ('\u{bd48}', '\u{bd48}', GC_LV), + ('\u{bd49}', '\u{bd63}', GC_LVT), ('\u{bd64}', '\u{bd64}', GC_LV), ('\u{bd65}', '\u{bd7f}', + GC_LVT), ('\u{bd80}', '\u{bd80}', GC_LV), ('\u{bd81}', '\u{bd9b}', GC_LVT), ('\u{bd9c}', + '\u{bd9c}', GC_LV), ('\u{bd9d}', '\u{bdb7}', GC_LVT), ('\u{bdb8}', '\u{bdb8}', GC_LV), + ('\u{bdb9}', '\u{bdd3}', GC_LVT), ('\u{bdd4}', '\u{bdd4}', GC_LV), ('\u{bdd5}', '\u{bdef}', + GC_LVT), ('\u{bdf0}', '\u{bdf0}', GC_LV), ('\u{bdf1}', '\u{be0b}', GC_LVT), ('\u{be0c}', + '\u{be0c}', GC_LV), ('\u{be0d}', '\u{be27}', GC_LVT), ('\u{be28}', '\u{be28}', GC_LV), + ('\u{be29}', '\u{be43}', GC_LVT), ('\u{be44}', '\u{be44}', GC_LV), ('\u{be45}', '\u{be5f}', + GC_LVT), ('\u{be60}', '\u{be60}', GC_LV), ('\u{be61}', '\u{be7b}', GC_LVT), ('\u{be7c}', + '\u{be7c}', GC_LV), ('\u{be7d}', '\u{be97}', GC_LVT), ('\u{be98}', '\u{be98}', GC_LV), + ('\u{be99}', '\u{beb3}', GC_LVT), ('\u{beb4}', '\u{beb4}', GC_LV), ('\u{beb5}', '\u{becf}', + GC_LVT), ('\u{bed0}', '\u{bed0}', GC_LV), ('\u{bed1}', '\u{beeb}', GC_LVT), ('\u{beec}', + '\u{beec}', GC_LV), ('\u{beed}', '\u{bf07}', GC_LVT), ('\u{bf08}', '\u{bf08}', GC_LV), + ('\u{bf09}', '\u{bf23}', GC_LVT), ('\u{bf24}', '\u{bf24}', GC_LV), ('\u{bf25}', '\u{bf3f}', + GC_LVT), ('\u{bf40}', '\u{bf40}', GC_LV), ('\u{bf41}', '\u{bf5b}', GC_LVT), ('\u{bf5c}', + '\u{bf5c}', GC_LV), ('\u{bf5d}', '\u{bf77}', GC_LVT), ('\u{bf78}', '\u{bf78}', GC_LV), + ('\u{bf79}', '\u{bf93}', GC_LVT), ('\u{bf94}', '\u{bf94}', GC_LV), ('\u{bf95}', '\u{bfaf}', + GC_LVT), ('\u{bfb0}', '\u{bfb0}', GC_LV), ('\u{bfb1}', '\u{bfcb}', GC_LVT), ('\u{bfcc}', + '\u{bfcc}', GC_LV), ('\u{bfcd}', '\u{bfe7}', GC_LVT), ('\u{bfe8}', '\u{bfe8}', GC_LV), + ('\u{bfe9}', '\u{c003}', GC_LVT), ('\u{c004}', '\u{c004}', GC_LV), ('\u{c005}', '\u{c01f}', + GC_LVT), ('\u{c020}', '\u{c020}', GC_LV), ('\u{c021}', '\u{c03b}', GC_LVT), ('\u{c03c}', + '\u{c03c}', GC_LV), ('\u{c03d}', '\u{c057}', GC_LVT), ('\u{c058}', '\u{c058}', GC_LV), + ('\u{c059}', '\u{c073}', GC_LVT), ('\u{c074}', '\u{c074}', GC_LV), ('\u{c075}', '\u{c08f}', + GC_LVT), ('\u{c090}', '\u{c090}', GC_LV), ('\u{c091}', '\u{c0ab}', GC_LVT), ('\u{c0ac}', + '\u{c0ac}', GC_LV), ('\u{c0ad}', '\u{c0c7}', GC_LVT), ('\u{c0c8}', '\u{c0c8}', GC_LV), + ('\u{c0c9}', '\u{c0e3}', GC_LVT), ('\u{c0e4}', '\u{c0e4}', GC_LV), ('\u{c0e5}', '\u{c0ff}', + GC_LVT), ('\u{c100}', '\u{c100}', GC_LV), ('\u{c101}', '\u{c11b}', GC_LVT), ('\u{c11c}', + '\u{c11c}', GC_LV), ('\u{c11d}', '\u{c137}', GC_LVT), ('\u{c138}', '\u{c138}', GC_LV), + ('\u{c139}', '\u{c153}', GC_LVT), ('\u{c154}', '\u{c154}', GC_LV), ('\u{c155}', '\u{c16f}', + GC_LVT), ('\u{c170}', '\u{c170}', GC_LV), ('\u{c171}', '\u{c18b}', GC_LVT), ('\u{c18c}', + '\u{c18c}', GC_LV), ('\u{c18d}', '\u{c1a7}', GC_LVT), ('\u{c1a8}', '\u{c1a8}', GC_LV), + ('\u{c1a9}', '\u{c1c3}', GC_LVT), ('\u{c1c4}', '\u{c1c4}', GC_LV), ('\u{c1c5}', '\u{c1df}', + GC_LVT), ('\u{c1e0}', '\u{c1e0}', GC_LV), ('\u{c1e1}', '\u{c1fb}', GC_LVT), ('\u{c1fc}', + '\u{c1fc}', GC_LV), ('\u{c1fd}', '\u{c217}', GC_LVT), ('\u{c218}', '\u{c218}', GC_LV), + ('\u{c219}', '\u{c233}', GC_LVT), ('\u{c234}', '\u{c234}', GC_LV), ('\u{c235}', '\u{c24f}', + GC_LVT), ('\u{c250}', '\u{c250}', GC_LV), ('\u{c251}', '\u{c26b}', GC_LVT), ('\u{c26c}', + '\u{c26c}', GC_LV), ('\u{c26d}', '\u{c287}', GC_LVT), ('\u{c288}', '\u{c288}', GC_LV), + ('\u{c289}', '\u{c2a3}', GC_LVT), ('\u{c2a4}', '\u{c2a4}', GC_LV), ('\u{c2a5}', '\u{c2bf}', + GC_LVT), ('\u{c2c0}', '\u{c2c0}', GC_LV), ('\u{c2c1}', '\u{c2db}', GC_LVT), ('\u{c2dc}', + '\u{c2dc}', GC_LV), ('\u{c2dd}', '\u{c2f7}', GC_LVT), ('\u{c2f8}', '\u{c2f8}', GC_LV), + ('\u{c2f9}', '\u{c313}', GC_LVT), ('\u{c314}', '\u{c314}', GC_LV), ('\u{c315}', '\u{c32f}', + GC_LVT), ('\u{c330}', '\u{c330}', GC_LV), ('\u{c331}', '\u{c34b}', GC_LVT), ('\u{c34c}', + '\u{c34c}', GC_LV), ('\u{c34d}', '\u{c367}', GC_LVT), ('\u{c368}', '\u{c368}', GC_LV), + ('\u{c369}', '\u{c383}', GC_LVT), ('\u{c384}', '\u{c384}', GC_LV), ('\u{c385}', '\u{c39f}', + GC_LVT), ('\u{c3a0}', '\u{c3a0}', GC_LV), ('\u{c3a1}', '\u{c3bb}', GC_LVT), ('\u{c3bc}', + '\u{c3bc}', GC_LV), ('\u{c3bd}', '\u{c3d7}', GC_LVT), ('\u{c3d8}', '\u{c3d8}', GC_LV), + ('\u{c3d9}', '\u{c3f3}', GC_LVT), ('\u{c3f4}', '\u{c3f4}', GC_LV), ('\u{c3f5}', '\u{c40f}', + GC_LVT), ('\u{c410}', '\u{c410}', GC_LV), ('\u{c411}', '\u{c42b}', GC_LVT), ('\u{c42c}', + '\u{c42c}', GC_LV), ('\u{c42d}', '\u{c447}', GC_LVT), ('\u{c448}', '\u{c448}', GC_LV), + ('\u{c449}', '\u{c463}', GC_LVT), ('\u{c464}', '\u{c464}', GC_LV), ('\u{c465}', '\u{c47f}', + GC_LVT), ('\u{c480}', '\u{c480}', GC_LV), ('\u{c481}', '\u{c49b}', GC_LVT), ('\u{c49c}', + '\u{c49c}', GC_LV), ('\u{c49d}', '\u{c4b7}', GC_LVT), ('\u{c4b8}', '\u{c4b8}', GC_LV), + ('\u{c4b9}', '\u{c4d3}', GC_LVT), ('\u{c4d4}', '\u{c4d4}', GC_LV), ('\u{c4d5}', '\u{c4ef}', + GC_LVT), ('\u{c4f0}', '\u{c4f0}', GC_LV), ('\u{c4f1}', '\u{c50b}', GC_LVT), ('\u{c50c}', + '\u{c50c}', GC_LV), ('\u{c50d}', '\u{c527}', GC_LVT), ('\u{c528}', '\u{c528}', GC_LV), + ('\u{c529}', '\u{c543}', GC_LVT), ('\u{c544}', '\u{c544}', GC_LV), ('\u{c545}', '\u{c55f}', + GC_LVT), ('\u{c560}', '\u{c560}', GC_LV), ('\u{c561}', '\u{c57b}', GC_LVT), ('\u{c57c}', + '\u{c57c}', GC_LV), ('\u{c57d}', '\u{c597}', GC_LVT), ('\u{c598}', '\u{c598}', GC_LV), + ('\u{c599}', '\u{c5b3}', GC_LVT), ('\u{c5b4}', '\u{c5b4}', GC_LV), ('\u{c5b5}', '\u{c5cf}', + GC_LVT), ('\u{c5d0}', '\u{c5d0}', GC_LV), ('\u{c5d1}', '\u{c5eb}', GC_LVT), ('\u{c5ec}', + '\u{c5ec}', GC_LV), ('\u{c5ed}', '\u{c607}', GC_LVT), ('\u{c608}', '\u{c608}', GC_LV), + ('\u{c609}', '\u{c623}', GC_LVT), ('\u{c624}', '\u{c624}', GC_LV), ('\u{c625}', '\u{c63f}', + GC_LVT), ('\u{c640}', '\u{c640}', GC_LV), ('\u{c641}', '\u{c65b}', GC_LVT), ('\u{c65c}', + '\u{c65c}', GC_LV), ('\u{c65d}', '\u{c677}', GC_LVT), ('\u{c678}', '\u{c678}', GC_LV), + ('\u{c679}', '\u{c693}', GC_LVT), ('\u{c694}', '\u{c694}', GC_LV), ('\u{c695}', '\u{c6af}', + GC_LVT), ('\u{c6b0}', '\u{c6b0}', GC_LV), ('\u{c6b1}', '\u{c6cb}', GC_LVT), ('\u{c6cc}', + '\u{c6cc}', GC_LV), ('\u{c6cd}', '\u{c6e7}', GC_LVT), ('\u{c6e8}', '\u{c6e8}', GC_LV), + ('\u{c6e9}', '\u{c703}', GC_LVT), ('\u{c704}', '\u{c704}', GC_LV), ('\u{c705}', '\u{c71f}', + GC_LVT), ('\u{c720}', '\u{c720}', GC_LV), ('\u{c721}', '\u{c73b}', GC_LVT), ('\u{c73c}', + '\u{c73c}', GC_LV), ('\u{c73d}', '\u{c757}', GC_LVT), ('\u{c758}', '\u{c758}', GC_LV), + ('\u{c759}', '\u{c773}', GC_LVT), ('\u{c774}', '\u{c774}', GC_LV), ('\u{c775}', '\u{c78f}', + GC_LVT), ('\u{c790}', '\u{c790}', GC_LV), ('\u{c791}', '\u{c7ab}', GC_LVT), ('\u{c7ac}', + '\u{c7ac}', GC_LV), ('\u{c7ad}', '\u{c7c7}', GC_LVT), ('\u{c7c8}', '\u{c7c8}', GC_LV), + ('\u{c7c9}', '\u{c7e3}', GC_LVT), ('\u{c7e4}', '\u{c7e4}', GC_LV), ('\u{c7e5}', '\u{c7ff}', + GC_LVT), ('\u{c800}', '\u{c800}', GC_LV), ('\u{c801}', '\u{c81b}', GC_LVT), ('\u{c81c}', + '\u{c81c}', GC_LV), ('\u{c81d}', '\u{c837}', GC_LVT), ('\u{c838}', '\u{c838}', GC_LV), + ('\u{c839}', '\u{c853}', GC_LVT), ('\u{c854}', '\u{c854}', GC_LV), ('\u{c855}', '\u{c86f}', + GC_LVT), ('\u{c870}', '\u{c870}', GC_LV), ('\u{c871}', '\u{c88b}', GC_LVT), ('\u{c88c}', + '\u{c88c}', GC_LV), ('\u{c88d}', '\u{c8a7}', GC_LVT), ('\u{c8a8}', '\u{c8a8}', GC_LV), + ('\u{c8a9}', '\u{c8c3}', GC_LVT), ('\u{c8c4}', '\u{c8c4}', GC_LV), ('\u{c8c5}', '\u{c8df}', + GC_LVT), ('\u{c8e0}', '\u{c8e0}', GC_LV), ('\u{c8e1}', '\u{c8fb}', GC_LVT), ('\u{c8fc}', + '\u{c8fc}', GC_LV), ('\u{c8fd}', '\u{c917}', GC_LVT), ('\u{c918}', '\u{c918}', GC_LV), + ('\u{c919}', '\u{c933}', GC_LVT), ('\u{c934}', '\u{c934}', GC_LV), ('\u{c935}', '\u{c94f}', + GC_LVT), ('\u{c950}', '\u{c950}', GC_LV), ('\u{c951}', '\u{c96b}', GC_LVT), ('\u{c96c}', + '\u{c96c}', GC_LV), ('\u{c96d}', '\u{c987}', GC_LVT), ('\u{c988}', '\u{c988}', GC_LV), + ('\u{c989}', '\u{c9a3}', GC_LVT), ('\u{c9a4}', '\u{c9a4}', GC_LV), ('\u{c9a5}', '\u{c9bf}', + GC_LVT), ('\u{c9c0}', '\u{c9c0}', GC_LV), ('\u{c9c1}', '\u{c9db}', GC_LVT), ('\u{c9dc}', + '\u{c9dc}', GC_LV), ('\u{c9dd}', '\u{c9f7}', GC_LVT), ('\u{c9f8}', '\u{c9f8}', GC_LV), + ('\u{c9f9}', '\u{ca13}', GC_LVT), ('\u{ca14}', '\u{ca14}', GC_LV), ('\u{ca15}', '\u{ca2f}', + GC_LVT), ('\u{ca30}', '\u{ca30}', GC_LV), ('\u{ca31}', '\u{ca4b}', GC_LVT), ('\u{ca4c}', + '\u{ca4c}', GC_LV), ('\u{ca4d}', '\u{ca67}', GC_LVT), ('\u{ca68}', '\u{ca68}', GC_LV), + ('\u{ca69}', '\u{ca83}', GC_LVT), ('\u{ca84}', '\u{ca84}', GC_LV), ('\u{ca85}', '\u{ca9f}', + GC_LVT), ('\u{caa0}', '\u{caa0}', GC_LV), ('\u{caa1}', '\u{cabb}', GC_LVT), ('\u{cabc}', + '\u{cabc}', GC_LV), ('\u{cabd}', '\u{cad7}', GC_LVT), ('\u{cad8}', '\u{cad8}', GC_LV), + ('\u{cad9}', '\u{caf3}', GC_LVT), ('\u{caf4}', '\u{caf4}', GC_LV), ('\u{caf5}', '\u{cb0f}', + GC_LVT), ('\u{cb10}', '\u{cb10}', GC_LV), ('\u{cb11}', '\u{cb2b}', GC_LVT), ('\u{cb2c}', + '\u{cb2c}', GC_LV), ('\u{cb2d}', '\u{cb47}', GC_LVT), ('\u{cb48}', '\u{cb48}', GC_LV), + ('\u{cb49}', '\u{cb63}', GC_LVT), ('\u{cb64}', '\u{cb64}', GC_LV), ('\u{cb65}', '\u{cb7f}', + GC_LVT), ('\u{cb80}', '\u{cb80}', GC_LV), ('\u{cb81}', '\u{cb9b}', GC_LVT), ('\u{cb9c}', + '\u{cb9c}', GC_LV), ('\u{cb9d}', '\u{cbb7}', GC_LVT), ('\u{cbb8}', '\u{cbb8}', GC_LV), + ('\u{cbb9}', '\u{cbd3}', GC_LVT), ('\u{cbd4}', '\u{cbd4}', GC_LV), ('\u{cbd5}', '\u{cbef}', + GC_LVT), ('\u{cbf0}', '\u{cbf0}', GC_LV), ('\u{cbf1}', '\u{cc0b}', GC_LVT), ('\u{cc0c}', + '\u{cc0c}', GC_LV), ('\u{cc0d}', '\u{cc27}', GC_LVT), ('\u{cc28}', '\u{cc28}', GC_LV), + ('\u{cc29}', '\u{cc43}', GC_LVT), ('\u{cc44}', '\u{cc44}', GC_LV), ('\u{cc45}', '\u{cc5f}', + GC_LVT), ('\u{cc60}', '\u{cc60}', GC_LV), ('\u{cc61}', '\u{cc7b}', GC_LVT), ('\u{cc7c}', + '\u{cc7c}', GC_LV), ('\u{cc7d}', '\u{cc97}', GC_LVT), ('\u{cc98}', '\u{cc98}', GC_LV), + ('\u{cc99}', '\u{ccb3}', GC_LVT), ('\u{ccb4}', '\u{ccb4}', GC_LV), ('\u{ccb5}', '\u{cccf}', + GC_LVT), ('\u{ccd0}', '\u{ccd0}', GC_LV), ('\u{ccd1}', '\u{cceb}', GC_LVT), ('\u{ccec}', + '\u{ccec}', GC_LV), ('\u{cced}', '\u{cd07}', GC_LVT), ('\u{cd08}', '\u{cd08}', GC_LV), + ('\u{cd09}', '\u{cd23}', GC_LVT), ('\u{cd24}', '\u{cd24}', GC_LV), ('\u{cd25}', '\u{cd3f}', + GC_LVT), ('\u{cd40}', '\u{cd40}', GC_LV), ('\u{cd41}', '\u{cd5b}', GC_LVT), ('\u{cd5c}', + '\u{cd5c}', GC_LV), ('\u{cd5d}', '\u{cd77}', GC_LVT), ('\u{cd78}', '\u{cd78}', GC_LV), + ('\u{cd79}', '\u{cd93}', GC_LVT), ('\u{cd94}', '\u{cd94}', GC_LV), ('\u{cd95}', '\u{cdaf}', + GC_LVT), ('\u{cdb0}', '\u{cdb0}', GC_LV), ('\u{cdb1}', '\u{cdcb}', GC_LVT), ('\u{cdcc}', + '\u{cdcc}', GC_LV), ('\u{cdcd}', '\u{cde7}', GC_LVT), ('\u{cde8}', '\u{cde8}', GC_LV), + ('\u{cde9}', '\u{ce03}', GC_LVT), ('\u{ce04}', '\u{ce04}', GC_LV), ('\u{ce05}', '\u{ce1f}', + GC_LVT), ('\u{ce20}', '\u{ce20}', GC_LV), ('\u{ce21}', '\u{ce3b}', GC_LVT), ('\u{ce3c}', + '\u{ce3c}', GC_LV), ('\u{ce3d}', '\u{ce57}', GC_LVT), ('\u{ce58}', '\u{ce58}', GC_LV), + ('\u{ce59}', '\u{ce73}', GC_LVT), ('\u{ce74}', '\u{ce74}', GC_LV), ('\u{ce75}', '\u{ce8f}', + GC_LVT), ('\u{ce90}', '\u{ce90}', GC_LV), ('\u{ce91}', '\u{ceab}', GC_LVT), ('\u{ceac}', + '\u{ceac}', GC_LV), ('\u{cead}', '\u{cec7}', GC_LVT), ('\u{cec8}', '\u{cec8}', GC_LV), + ('\u{cec9}', '\u{cee3}', GC_LVT), ('\u{cee4}', '\u{cee4}', GC_LV), ('\u{cee5}', '\u{ceff}', + GC_LVT), ('\u{cf00}', '\u{cf00}', GC_LV), ('\u{cf01}', '\u{cf1b}', GC_LVT), ('\u{cf1c}', + '\u{cf1c}', GC_LV), ('\u{cf1d}', '\u{cf37}', GC_LVT), ('\u{cf38}', '\u{cf38}', GC_LV), + ('\u{cf39}', '\u{cf53}', GC_LVT), ('\u{cf54}', '\u{cf54}', GC_LV), ('\u{cf55}', '\u{cf6f}', + GC_LVT), ('\u{cf70}', '\u{cf70}', GC_LV), ('\u{cf71}', '\u{cf8b}', GC_LVT), ('\u{cf8c}', + '\u{cf8c}', GC_LV), ('\u{cf8d}', '\u{cfa7}', GC_LVT), ('\u{cfa8}', '\u{cfa8}', GC_LV), + ('\u{cfa9}', '\u{cfc3}', GC_LVT), ('\u{cfc4}', '\u{cfc4}', GC_LV), ('\u{cfc5}', '\u{cfdf}', + GC_LVT), ('\u{cfe0}', '\u{cfe0}', GC_LV), ('\u{cfe1}', '\u{cffb}', GC_LVT), ('\u{cffc}', + '\u{cffc}', GC_LV), ('\u{cffd}', '\u{d017}', GC_LVT), ('\u{d018}', '\u{d018}', GC_LV), + ('\u{d019}', '\u{d033}', GC_LVT), ('\u{d034}', '\u{d034}', GC_LV), ('\u{d035}', '\u{d04f}', + GC_LVT), ('\u{d050}', '\u{d050}', GC_LV), ('\u{d051}', '\u{d06b}', GC_LVT), ('\u{d06c}', + '\u{d06c}', GC_LV), ('\u{d06d}', '\u{d087}', GC_LVT), ('\u{d088}', '\u{d088}', GC_LV), + ('\u{d089}', '\u{d0a3}', GC_LVT), ('\u{d0a4}', '\u{d0a4}', GC_LV), ('\u{d0a5}', '\u{d0bf}', + GC_LVT), ('\u{d0c0}', '\u{d0c0}', GC_LV), ('\u{d0c1}', '\u{d0db}', GC_LVT), ('\u{d0dc}', + '\u{d0dc}', GC_LV), ('\u{d0dd}', '\u{d0f7}', GC_LVT), ('\u{d0f8}', '\u{d0f8}', GC_LV), + ('\u{d0f9}', '\u{d113}', GC_LVT), ('\u{d114}', '\u{d114}', GC_LV), ('\u{d115}', '\u{d12f}', + GC_LVT), ('\u{d130}', '\u{d130}', GC_LV), ('\u{d131}', '\u{d14b}', GC_LVT), ('\u{d14c}', + '\u{d14c}', GC_LV), ('\u{d14d}', '\u{d167}', GC_LVT), ('\u{d168}', '\u{d168}', GC_LV), + ('\u{d169}', '\u{d183}', GC_LVT), ('\u{d184}', '\u{d184}', GC_LV), ('\u{d185}', '\u{d19f}', + GC_LVT), ('\u{d1a0}', '\u{d1a0}', GC_LV), ('\u{d1a1}', '\u{d1bb}', GC_LVT), ('\u{d1bc}', + '\u{d1bc}', GC_LV), ('\u{d1bd}', '\u{d1d7}', GC_LVT), ('\u{d1d8}', '\u{d1d8}', GC_LV), + ('\u{d1d9}', '\u{d1f3}', GC_LVT), ('\u{d1f4}', '\u{d1f4}', GC_LV), ('\u{d1f5}', '\u{d20f}', + GC_LVT), ('\u{d210}', '\u{d210}', GC_LV), ('\u{d211}', '\u{d22b}', GC_LVT), ('\u{d22c}', + '\u{d22c}', GC_LV), ('\u{d22d}', '\u{d247}', GC_LVT), ('\u{d248}', '\u{d248}', GC_LV), + ('\u{d249}', '\u{d263}', GC_LVT), ('\u{d264}', '\u{d264}', GC_LV), ('\u{d265}', '\u{d27f}', + GC_LVT), ('\u{d280}', '\u{d280}', GC_LV), ('\u{d281}', '\u{d29b}', GC_LVT), ('\u{d29c}', + '\u{d29c}', GC_LV), ('\u{d29d}', '\u{d2b7}', GC_LVT), ('\u{d2b8}', '\u{d2b8}', GC_LV), + ('\u{d2b9}', '\u{d2d3}', GC_LVT), ('\u{d2d4}', '\u{d2d4}', GC_LV), ('\u{d2d5}', '\u{d2ef}', + GC_LVT), ('\u{d2f0}', '\u{d2f0}', GC_LV), ('\u{d2f1}', '\u{d30b}', GC_LVT), ('\u{d30c}', + '\u{d30c}', GC_LV), ('\u{d30d}', '\u{d327}', GC_LVT), ('\u{d328}', '\u{d328}', GC_LV), + ('\u{d329}', '\u{d343}', GC_LVT), ('\u{d344}', '\u{d344}', GC_LV), ('\u{d345}', '\u{d35f}', + GC_LVT), ('\u{d360}', '\u{d360}', GC_LV), ('\u{d361}', '\u{d37b}', GC_LVT), ('\u{d37c}', + '\u{d37c}', GC_LV), ('\u{d37d}', '\u{d397}', GC_LVT), ('\u{d398}', '\u{d398}', GC_LV), + ('\u{d399}', '\u{d3b3}', GC_LVT), ('\u{d3b4}', '\u{d3b4}', GC_LV), ('\u{d3b5}', '\u{d3cf}', + GC_LVT), ('\u{d3d0}', '\u{d3d0}', GC_LV), ('\u{d3d1}', '\u{d3eb}', GC_LVT), ('\u{d3ec}', + '\u{d3ec}', GC_LV), ('\u{d3ed}', '\u{d407}', GC_LVT), ('\u{d408}', '\u{d408}', GC_LV), + ('\u{d409}', '\u{d423}', GC_LVT), ('\u{d424}', '\u{d424}', GC_LV), ('\u{d425}', '\u{d43f}', + GC_LVT), ('\u{d440}', '\u{d440}', GC_LV), ('\u{d441}', '\u{d45b}', GC_LVT), ('\u{d45c}', + '\u{d45c}', GC_LV), ('\u{d45d}', '\u{d477}', GC_LVT), ('\u{d478}', '\u{d478}', GC_LV), + ('\u{d479}', '\u{d493}', GC_LVT), ('\u{d494}', '\u{d494}', GC_LV), ('\u{d495}', '\u{d4af}', + GC_LVT), ('\u{d4b0}', '\u{d4b0}', GC_LV), ('\u{d4b1}', '\u{d4cb}', GC_LVT), ('\u{d4cc}', + '\u{d4cc}', GC_LV), ('\u{d4cd}', '\u{d4e7}', GC_LVT), ('\u{d4e8}', '\u{d4e8}', GC_LV), + ('\u{d4e9}', '\u{d503}', GC_LVT), ('\u{d504}', '\u{d504}', GC_LV), ('\u{d505}', '\u{d51f}', + GC_LVT), ('\u{d520}', '\u{d520}', GC_LV), ('\u{d521}', '\u{d53b}', GC_LVT), ('\u{d53c}', + '\u{d53c}', GC_LV), ('\u{d53d}', '\u{d557}', GC_LVT), ('\u{d558}', '\u{d558}', GC_LV), + ('\u{d559}', '\u{d573}', GC_LVT), ('\u{d574}', '\u{d574}', GC_LV), ('\u{d575}', '\u{d58f}', + GC_LVT), ('\u{d590}', '\u{d590}', GC_LV), ('\u{d591}', '\u{d5ab}', GC_LVT), ('\u{d5ac}', + '\u{d5ac}', GC_LV), ('\u{d5ad}', '\u{d5c7}', GC_LVT), ('\u{d5c8}', '\u{d5c8}', GC_LV), + ('\u{d5c9}', '\u{d5e3}', GC_LVT), ('\u{d5e4}', '\u{d5e4}', GC_LV), ('\u{d5e5}', '\u{d5ff}', + GC_LVT), ('\u{d600}', '\u{d600}', GC_LV), ('\u{d601}', '\u{d61b}', GC_LVT), ('\u{d61c}', + '\u{d61c}', GC_LV), ('\u{d61d}', '\u{d637}', GC_LVT), ('\u{d638}', '\u{d638}', GC_LV), + ('\u{d639}', '\u{d653}', GC_LVT), ('\u{d654}', '\u{d654}', GC_LV), ('\u{d655}', '\u{d66f}', + GC_LVT), ('\u{d670}', '\u{d670}', GC_LV), ('\u{d671}', '\u{d68b}', GC_LVT), ('\u{d68c}', + '\u{d68c}', GC_LV), ('\u{d68d}', '\u{d6a7}', GC_LVT), ('\u{d6a8}', '\u{d6a8}', GC_LV), + ('\u{d6a9}', '\u{d6c3}', GC_LVT), ('\u{d6c4}', '\u{d6c4}', GC_LV), ('\u{d6c5}', '\u{d6df}', + GC_LVT), ('\u{d6e0}', '\u{d6e0}', GC_LV), ('\u{d6e1}', '\u{d6fb}', GC_LVT), ('\u{d6fc}', + '\u{d6fc}', GC_LV), ('\u{d6fd}', '\u{d717}', GC_LVT), ('\u{d718}', '\u{d718}', GC_LV), + ('\u{d719}', '\u{d733}', GC_LVT), ('\u{d734}', '\u{d734}', GC_LV), ('\u{d735}', '\u{d74f}', + GC_LVT), ('\u{d750}', '\u{d750}', GC_LV), ('\u{d751}', '\u{d76b}', GC_LVT), ('\u{d76c}', + '\u{d76c}', GC_LV), ('\u{d76d}', '\u{d787}', GC_LVT), ('\u{d788}', '\u{d788}', GC_LV), + ('\u{d789}', '\u{d7a3}', GC_LVT), ('\u{d7b0}', '\u{d7c6}', GC_V), ('\u{d7cb}', '\u{d7fb}', + GC_T), ('\u{fb1e}', '\u{fb1e}', GC_Extend), ('\u{fe00}', '\u{fe0f}', GC_Extend), ('\u{fe20}', '\u{fe2d}', GC_Extend), ('\u{feff}', '\u{feff}', GC_Control), ('\u{ff9e}', '\u{ff9f}', GC_Extend), ('\u{fff0}', '\u{fffb}', GC_Control), ('\u{101fd}', '\u{101fd}', GC_Extend), ('\u{102e0}', '\u{102e0}', GC_Extend), ('\u{10376}', '\u{1037a}', GC_Extend), @@ -8326,7 +5332,7 @@ pub mod grapheme { ('\u{1d173}', '\u{1d17a}', GC_Control), ('\u{1d17b}', '\u{1d182}', GC_Extend), ('\u{1d185}', '\u{1d18b}', GC_Extend), ('\u{1d1aa}', '\u{1d1ad}', GC_Extend), ('\u{1d242}', '\u{1d244}', GC_Extend), ('\u{1e8d0}', '\u{1e8d6}', GC_Extend), ('\u{1f1e6}', '\u{1f1ff}', - GC_RegionalIndicator), ('\u{e0000}', '\u{e00ff}', GC_Control), ('\u{e0100}', '\u{e01ef}', + GC_Regional_Indicator), ('\u{e0000}', '\u{e00ff}', GC_Control), ('\u{e0100}', '\u{e01ef}', GC_Extend), ('\u{e01f0}', '\u{e0fff}', GC_Control) ]; diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 3f9dd8ab63..0e424ea0d7 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -20,7 +20,7 @@ use core::prelude::*; use core::char; use core::cmp; -use core::iter::{Filter, AdditiveIterator}; +use core::iter::Filter; use core::mem; use core::slice; use core::str::Split; @@ -28,7 +28,8 @@ use core::str::Split; use tables::grapheme::GraphemeCat; /// An iterator over the words of a string, separated by a sequence of whitespace -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "str_words", + reason = "words() will be replaced by split_whitespace() in 1.1.0")] pub struct Words<'a> { inner: Filter bool>, fn(&&str) -> bool>, } @@ -157,7 +158,7 @@ impl<'a> Iterator for Graphemes<'a> { #[inline] fn next(&mut self) -> Option<&'a str> { use tables::grapheme as gr; - if self.string.len() == 0 { + if self.string.is_empty() { return None; } @@ -199,7 +200,7 @@ impl<'a> Iterator for Graphemes<'a> { gr::GC_L => HangulL, gr::GC_LV | gr::GC_V => HangulLV, gr::GC_LVT | gr::GC_T => HangulLVT, - gr::GC_RegionalIndicator => Regional, + gr::GC_Regional_Indicator => Regional, _ => FindExtend }, FindExtend => { // found non-extending when looking for extending @@ -231,7 +232,7 @@ impl<'a> Iterator for Graphemes<'a> { } }, Regional => match cat { // rule GB8a - gr::GC_RegionalIndicator => continue, + gr::GC_Regional_Indicator => continue, _ => { take_curr = false; break; @@ -257,7 +258,7 @@ impl<'a> DoubleEndedIterator for Graphemes<'a> { #[inline] fn next_back(&mut self) -> Option<&'a str> { use tables::grapheme as gr; - if self.string.len() == 0 { + if self.string.is_empty() { return None; } @@ -300,7 +301,7 @@ impl<'a> DoubleEndedIterator for Graphemes<'a> { gr::GC_L | gr::GC_LV | gr::GC_LVT => HangulL, gr::GC_V => HangulLV, gr::GC_T => HangulLVT, - gr::GC_RegionalIndicator => Regional, + gr::GC_Regional_Indicator => Regional, gr::GC_Control => { take_curr = Start == state; break; @@ -332,7 +333,7 @@ impl<'a> DoubleEndedIterator for Graphemes<'a> { } }, Regional => match cat { // rule GB8a - gr::GC_RegionalIndicator => continue, + gr::GC_Regional_Indicator => continue, _ => { take_curr = false; break; diff --git a/src/llvm/utils/llvm-build/llvmbuild/__init__.pyc b/src/llvm/utils/llvm-build/llvmbuild/__init__.pyc index 2e54cec98e1ea812e1b31a07edd016b7a5c1873d..06d0c90e796c8be21f2ced311965830874483771 100644 GIT binary patch delta 15 WcmZo=YGq<){>;mjb<=tx`#%68*9A8K delta 15 WcmZo=YGq<){>;m@E>CtM`#%67-~{pj diff --git a/src/llvm/utils/llvm-build/llvmbuild/componentinfo.pyc b/src/llvm/utils/llvm-build/llvmbuild/componentinfo.pyc index ed79c29d915060382c1320b1feba715df9696f33..9fcd7b7ca55dbaa0f316399d25a4cdf2fc0179d7 100644 GIT binary patch delta 18 acmZ2Fk8$ZdMt0`Uyj)o~tv9mE`2zqy)doNS delta 18 acmZ2Fk8$ZdMt0`Uyj<(@WH++Q`2zqxnFad* diff --git a/src/llvm/utils/llvm-build/llvmbuild/configutil.pyc b/src/llvm/utils/llvm-build/llvmbuild/configutil.pyc index 09c8c6722899cbd1d2713fff2718bc81f2d4ea0d..02353b69cc264492c3cf70c9e19a70e38105c159 100644 GIT binary patch delta 16 XcmbO&Fk66~`7>?ZhD&7RW delta 16 XcmbO&Fk66~`7>?ZhDWU{; diff --git a/src/llvm/utils/llvm-build/llvmbuild/main.pyc b/src/llvm/utils/llvm-build/llvmbuild/main.pyc index 3e356bb998aa539e1aa748ac1d7e92ef48e733e3..ad9d9fafa3aeec24c122bc17960024a47ebca0fd 100644 GIT binary patch delta 18 ZcmZqq%-Hgok)8Q7FIU!0>y7NSl>kP^2QdHu delta 18 ZcmZqq%-Hgok)8Q7FW0&}*^TVAl>kMH2J8R; diff --git a/src/llvm/utils/llvm-build/llvmbuild/util.pyc b/src/llvm/utils/llvm-build/llvmbuild/util.pyc index cde42a973bedd57b70ad76a4351b64c6579535f9..5765bf491f6ef82b48928ff1abf57a30d67aecd4 100644 GIT binary patch delta 16 XcmaFE^M;3=`7iqN delta 16 XcmaFE^M;3=`7 Result> '\t' => 4, _ => unreachable!() } - }).sum() / 4 + 1; + }).sum::() / 4 + 1; if level > stack.len() + 1 { errors.push(format!("section '{}' is indented too deeply; \ diff --git a/src/rustbook/build.rs b/src/rustbook/build.rs index f06290b27c..f96704ee12 100644 --- a/src/rustbook/build.rs +++ b/src/rustbook/build.rs @@ -89,7 +89,8 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { } else { src = PathBuf::from(&env::args().nth(2).unwrap()); } - // preprocess the markdown, rerouting markdown references to html references + // preprocess the markdown, rerouting markdown references to html + // references let mut markdown_data = String::new(); try!(File::open(&src.join(&item.path)).and_then(|mut f| { f.read_to_string(&mut markdown_data) @@ -135,6 +136,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { format!("-o{}", out_path.display()), format!("--html-before-content={}", prelude.display()), format!("--html-after-content={}", postlude.display()), + format!("--markdown-playground-url=http://play.rust-lang.org"), format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()), "--markdown-no-toc".to_string(), ]; @@ -148,6 +150,14 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> { // create index.html from the root README try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))); + + // Copy some js for playpen + let mut jquery = try!(File::create(tgt.join("jquery.js"))); + let js = include_bytes!("../librustdoc/html/static/jquery-2.1.0.min.js"); + try!(jquery.write_all(js)); + let mut playpen = try!(File::create(tgt.join("playpen.js"))); + let js = include_bytes!("../librustdoc/html/static/playpen.js"); + try!(playpen.write_all(js)); Ok(()) } diff --git a/src/rustbook/javascript.rs b/src/rustbook/javascript.rs index 6ee8230e9f..d5483593aa 100644 --- a/src/rustbook/javascript.rs +++ b/src/rustbook/javascript.rs @@ -71,4 +71,6 @@ document.addEventListener("DOMContentLoaded", function(event) { }); + + "#; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 9a87c03f1c..31f75ae03b 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -77,6 +77,11 @@ extern "C" void LLVMRustPrintPassTimings() { TimerGroup::printAll(OS); } +extern "C" LLVMValueRef LLVMGetNamedValue(LLVMModuleRef M, + const char* Name) { + return wrap(unwrap(M)->getNamedValue(Name)); +} + extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, const char* Name, LLVMTypeRef FunctionTy) { @@ -84,6 +89,12 @@ extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, unwrap(FunctionTy))); } +extern "C" LLVMValueRef LLVMGetOrInsertGlobal(LLVMModuleRef M, + const char* Name, + LLVMTypeRef Ty) { + return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); +} + extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } diff --git a/src/test/auxiliary/coherence_copy_like_lib.rs b/src/test/auxiliary/coherence_copy_like_lib.rs index a1e1b48c2c..d3d389c6a8 100644 --- a/src/test/auxiliary/coherence_copy_like_lib.rs +++ b/src/test/auxiliary/coherence_copy_like_lib.rs @@ -11,9 +11,7 @@ #![crate_type = "rlib"] #![feature(fundamental)] -use std::marker::MarkerTrait; - -pub trait MyCopy : MarkerTrait { } +pub trait MyCopy { } impl MyCopy for i32 { } pub struct MyStruct(T); diff --git a/src/test/auxiliary/coherence_orphan_lib.rs b/src/test/auxiliary/coherence_orphan_lib.rs index 93d8fd3da8..b22d12300c 100644 --- a/src/test/auxiliary/coherence_orphan_lib.rs +++ b/src/test/auxiliary/coherence_orphan_lib.rs @@ -8,6 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub trait TheTrait : ::std::marker::PhantomFn { +pub trait TheTrait { fn the_fn(&self); } diff --git a/src/test/auxiliary/inline-default-methods.rs b/src/test/auxiliary/inline-default-methods.rs new file mode 100644 index 0000000000..5f1bd7ab52 --- /dev/null +++ b/src/test/auxiliary/inline-default-methods.rs @@ -0,0 +1,14 @@ +// 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. + +pub trait Foo { + fn bar(&self); + fn foo(&mut self) {} +} diff --git a/src/test/auxiliary/internal_unstable.rs b/src/test/auxiliary/internal_unstable.rs index 3d59b8e900..7f682d5d8d 100644 --- a/src/test/auxiliary/internal_unstable.rs +++ b/src/test/auxiliary/internal_unstable.rs @@ -22,6 +22,17 @@ pub struct Foo { pub x: u8 } +impl Foo { + #[unstable(feature = "method")] + pub fn method(&self) {} +} + +#[stable(feature = "stable", since = "1.0.0")] +pub struct Bar { + #[unstable(feature = "struct2_field")] + pub x: u8 +} + #[allow_internal_unstable] #[macro_export] macro_rules! call_unstable_allow { @@ -36,6 +47,18 @@ macro_rules! construct_unstable_allow { } } +#[allow_internal_unstable] +#[macro_export] +macro_rules! call_method_allow { + ($e: expr) => { $e.method() } +} + +#[allow_internal_unstable] +#[macro_export] +macro_rules! access_field_allow { + ($e: expr) => { $e.x } +} + #[allow_internal_unstable] #[macro_export] macro_rules! pass_through_allow { @@ -54,6 +77,16 @@ macro_rules! construct_unstable_noallow { } } +#[macro_export] +macro_rules! call_method_noallow { + ($e: expr) => { $e.method() } +} + +#[macro_export] +macro_rules! access_field_noallow { + ($e: expr) => { $e.x } +} + #[macro_export] macro_rules! pass_through_noallow { ($e: expr) => { $e } diff --git a/src/test/auxiliary/issue-11224.rs b/src/test/auxiliary/issue-11224.rs index 21935b6b9a..15b72b3778 100644 --- a/src/test/auxiliary/issue-11224.rs +++ b/src/test/auxiliary/issue-11224.rs @@ -21,6 +21,6 @@ mod inner { } pub fn foo() { - let a = &1is as &inner::Trait; + let a = &1isize as &inner::Trait; a.f(); } diff --git a/src/test/run-make/rustdoc-extern-default-method/lib.rs b/src/test/auxiliary/issue-13698.rs similarity index 81% rename from src/test/run-make/rustdoc-extern-default-method/lib.rs rename to src/test/auxiliary/issue-13698.rs index df92764dc9..0bb2133c83 100644 --- a/src/test/run-make/rustdoc-extern-default-method/lib.rs +++ b/src/test/auxiliary/issue-13698.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate ext; +pub trait Foo { + #[doc(hidden)] + fn foo(&self) {} +} -// @count lib/struct.Struct.html '//*[@id="method.provided"]' 1 -pub use ext::Struct; +impl Foo for i32 {} diff --git a/src/test/auxiliary/issue-15318.rs b/src/test/auxiliary/issue-15318.rs new file mode 100644 index 0000000000..9e42dbfbc6 --- /dev/null +++ b/src/test/auxiliary/issue-15318.rs @@ -0,0 +1,15 @@ +// 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. + +#![doc(html_root_url = "http://example.com/")] + +/// dox +#[doc(primitive = "pointer")] +pub mod ptr {} diff --git a/src/test/auxiliary/issue-17476.rs b/src/test/auxiliary/issue-17476.rs new file mode 100644 index 0000000000..d3a8603574 --- /dev/null +++ b/src/test/auxiliary/issue-17476.rs @@ -0,0 +1,16 @@ +// 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. + + +#![doc(html_root_url = "http://example.com")] + +pub trait Foo { + fn foo(&self) {} +} diff --git a/src/test/auxiliary/issue-20646.rs b/src/test/auxiliary/issue-20646.rs new file mode 100644 index 0000000000..150d8018f0 --- /dev/null +++ b/src/test/auxiliary/issue-20646.rs @@ -0,0 +1,15 @@ +// 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. + +pub trait Trait { + type Output; +} + +pub fn fun(_: T) where T: Trait {} diff --git a/src/test/auxiliary/issue-20727.rs b/src/test/auxiliary/issue-20727.rs new file mode 100644 index 0000000000..aea8b429d9 --- /dev/null +++ b/src/test/auxiliary/issue-20727.rs @@ -0,0 +1,38 @@ +// 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. + +pub trait Deref { + type Target: ?Sized; + + fn deref<'a>(&'a self) -> &'a Self::Target; +} + +pub trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + + +pub trait Bar {} +pub trait Deref2 { + type Target: Bar; + + fn deref(&self) -> Self::Target; +} + +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +pub trait IndexMut: Index { + fn index_mut(&mut self, index: Idx) -> &mut Self::Output; +} diff --git a/src/test/auxiliary/issue-21092.rs b/src/test/auxiliary/issue-21092.rs new file mode 100644 index 0000000000..6d6046cc7b --- /dev/null +++ b/src/test/auxiliary/issue-21092.rs @@ -0,0 +1,20 @@ +// 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. + +pub trait Foo { + type Bar; + fn foo(&self) {} +} + +pub struct Bar; + +impl Foo for Bar { + type Bar = i32; +} diff --git a/src/test/auxiliary/issue-21801.rs b/src/test/auxiliary/issue-21801.rs new file mode 100644 index 0000000000..ada6c69250 --- /dev/null +++ b/src/test/auxiliary/issue-21801.rs @@ -0,0 +1,17 @@ +// 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. + +pub struct Foo; + +impl Foo { + pub fn new(f: F) -> Foo where F: FnMut() -> i32 { + loop {} + } +} diff --git a/src/test/auxiliary/issue-22025.rs b/src/test/auxiliary/issue-22025.rs new file mode 100644 index 0000000000..554b580ae2 --- /dev/null +++ b/src/test/auxiliary/issue-22025.rs @@ -0,0 +1,18 @@ +// 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. + +pub mod foo { + + pub trait Foo {} + pub struct Bar; + + impl Foo for Bar {} + +} diff --git a/src/test/compile-fail/issue-22426-2.rs b/src/test/auxiliary/issue-23207-1.rs similarity index 90% rename from src/test/compile-fail/issue-22426-2.rs rename to src/test/auxiliary/issue-23207-1.rs index ea5180e3ee..ec9f2004eb 100644 --- a/src/test/compile-fail/issue-22426-2.rs +++ b/src/test/auxiliary/issue-23207-1.rs @@ -8,5 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn a(B<) {} - //~^ error: unexpected token: `<` +pub mod fmt { + pub struct Error; +} diff --git a/src/test/auxiliary/issue-23207-2.rs b/src/test/auxiliary/issue-23207-2.rs new file mode 100644 index 0000000000..5e9c540ab6 --- /dev/null +++ b/src/test/auxiliary/issue-23207-2.rs @@ -0,0 +1,16 @@ +// 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. + +extern crate issue_23207_1; + +pub mod fmt { + pub use issue_23207_1::fmt::Error; +} + diff --git a/src/test/auxiliary/issue_3907.rs b/src/test/auxiliary/issue_3907.rs index 3d5e52d709..6472c08c22 100644 --- a/src/test/auxiliary/issue_3907.rs +++ b/src/test/auxiliary/issue_3907.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -use std::marker::MarkerTrait; - -pub trait Foo : MarkerTrait { +pub trait Foo { fn bar(); } diff --git a/src/test/auxiliary/lang-item-public.rs b/src/test/auxiliary/lang-item-public.rs index 72dfc75f41..d195bd7e77 100644 --- a/src/test/auxiliary/lang-item-public.rs +++ b/src/test/auxiliary/lang-item-public.rs @@ -12,12 +12,8 @@ #![no_std] #![feature(lang_items)] -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } - #[lang="sized"] -pub trait Sized : PhantomFn {} +pub trait Sized { } #[lang="panic"] fn panic(_: &(&'static str, &'static str, usize)) -> ! { loop {} } @@ -29,7 +25,7 @@ extern fn stack_exhausted() {} extern fn eh_personality() {} #[lang="copy"] -pub trait Copy : PhantomFn { +pub trait Copy { // Empty. } diff --git a/src/test/auxiliary/llvm_pass_plugin.rs b/src/test/auxiliary/llvm_pass_plugin.rs new file mode 100644 index 0000000000..d61f47fd7e --- /dev/null +++ b/src/test/auxiliary/llvm_pass_plugin.rs @@ -0,0 +1,28 @@ +// 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. + +// force-host + +#![feature(plugin_registrar)] +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::plugin::Registry; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + // This pass is built in to LLVM. + // + // Normally, we would name a pass that was registered through + // C++ static object constructors in the same .so file as the + // plugin registrar. + reg.register_llvm_pass("inline"); +} diff --git a/src/test/auxiliary/private_trait_xc.rs b/src/test/auxiliary/private_trait_xc.rs index dc08033602..37ee10c8d3 100644 --- a/src/test/auxiliary/private_trait_xc.rs +++ b/src/test/auxiliary/private_trait_xc.rs @@ -8,6 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -trait Foo : ::std::marker::MarkerTrait {} +trait Foo {} diff --git a/src/test/run-make/rustdoc-default-impl/foo.rs b/src/test/auxiliary/rustdoc-default-impl.rs similarity index 94% rename from src/test/run-make/rustdoc-default-impl/foo.rs rename to src/test/auxiliary/rustdoc-default-impl.rs index 8f11629be6..c2ff7a0054 100644 --- a/src/test/run-make/rustdoc-default-impl/foo.rs +++ b/src/test/auxiliary/rustdoc-default-impl.rs @@ -14,7 +14,7 @@ pub mod bar { use std::marker; - pub trait Bar: marker::MarkerTrait + 'static {} + pub trait Bar: 'static {} impl Bar for .. {} diff --git a/src/test/run-make/rustdoc-extern-default-method/ext.rs b/src/test/auxiliary/rustdoc-extern-default-method.rs similarity index 100% rename from src/test/run-make/rustdoc-extern-default-method/ext.rs rename to src/test/auxiliary/rustdoc-extern-default-method.rs diff --git a/src/test/run-make/rustdoc-extern-method/foo.rs b/src/test/auxiliary/rustdoc-extern-method.rs similarity index 100% rename from src/test/run-make/rustdoc-extern-method/foo.rs rename to src/test/auxiliary/rustdoc-extern-method.rs diff --git a/src/test/run-make/rustdoc-ffi/lib.rs b/src/test/auxiliary/rustdoc-ffi.rs similarity index 100% rename from src/test/run-make/rustdoc-ffi/lib.rs rename to src/test/auxiliary/rustdoc-ffi.rs diff --git a/src/test/auxiliary/svh-a-base.rs b/src/test/auxiliary/svh-a-base.rs index 7e10d2158e..31a97f695f 100644 --- a/src/test/auxiliary/svh-a-base.rs +++ b/src/test/auxiliary/svh-a-base.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-lit.rs b/src/test/auxiliary/svh-a-change-lit.rs index c5f3880551..5339fc8295 100644 --- a/src/test/auxiliary/svh-a-change-lit.rs +++ b/src/test/auxiliary/svh-a-change-lit.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-significant-cfg.rs b/src/test/auxiliary/svh-a-change-significant-cfg.rs index 3168e747eb..2a5d9446f8 100644 --- a/src/test/auxiliary/svh-a-change-significant-cfg.rs +++ b/src/test/auxiliary/svh-a-change-significant-cfg.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-trait-bound.rs b/src/test/auxiliary/svh-a-change-trait-bound.rs index f86a43494f..61f2f2803a 100644 --- a/src/test/auxiliary/svh-a-change-trait-bound.rs +++ b/src/test/auxiliary/svh-a-change-trait-bound.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-type-arg.rs b/src/test/auxiliary/svh-a-change-type-arg.rs index dc412b7004..270ce95be2 100644 --- a/src/test/auxiliary/svh-a-change-type-arg.rs +++ b/src/test/auxiliary/svh-a-change-type-arg.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-type-ret.rs b/src/test/auxiliary/svh-a-change-type-ret.rs index 0cfcbbb055..de4cc85a7d 100644 --- a/src/test/auxiliary/svh-a-change-type-ret.rs +++ b/src/test/auxiliary/svh-a-change-type-ret.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-change-type-static.rs b/src/test/auxiliary/svh-a-change-type-static.rs index e1e32095b5..62f7986f1c 100644 --- a/src/test/auxiliary/svh-a-change-type-static.rs +++ b/src/test/auxiliary/svh-a-change-type-static.rs @@ -16,14 +16,12 @@ #![crate_name = "a"] #![feature(core)] -use std::marker::MarkerTrait; - macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-comment.rs b/src/test/auxiliary/svh-a-comment.rs index 9fd97376b6..22e40822ee 100644 --- a/src/test/auxiliary/svh-a-comment.rs +++ b/src/test/auxiliary/svh-a-comment.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-doc.rs b/src/test/auxiliary/svh-a-doc.rs index e64bde096b..3d8a728967 100644 --- a/src/test/auxiliary/svh-a-doc.rs +++ b/src/test/auxiliary/svh-a-doc.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-macro.rs b/src/test/auxiliary/svh-a-macro.rs index b16338f1e1..41d7eb7b18 100644 --- a/src/test/auxiliary/svh-a-macro.rs +++ b/src/test/auxiliary/svh-a-macro.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-no-change.rs b/src/test/auxiliary/svh-a-no-change.rs index 7e10d2158e..31a97f695f 100644 --- a/src/test/auxiliary/svh-a-no-change.rs +++ b/src/test/auxiliary/svh-a-no-change.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-redundant-cfg.rs b/src/test/auxiliary/svh-a-redundant-cfg.rs index 8cadd7bdf4..e405c337ab 100644 --- a/src/test/auxiliary/svh-a-redundant-cfg.rs +++ b/src/test/auxiliary/svh-a-redundant-cfg.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/svh-a-whitespace.rs b/src/test/auxiliary/svh-a-whitespace.rs index fcaf779095..9ef788c984 100644 --- a/src/test/auxiliary/svh-a-whitespace.rs +++ b/src/test/auxiliary/svh-a-whitespace.rs @@ -14,16 +14,13 @@ //! (#14132). #![crate_name = "a"] -#![feature(core)] - -use std::marker::MarkerTrait; macro_rules! three { () => { 3 } } -pub trait U : MarkerTrait {} -pub trait V : MarkerTrait {} +pub trait U {} +pub trait V {} impl U for () {} impl V for () {} diff --git a/src/test/auxiliary/trait_impl_conflict.rs b/src/test/auxiliary/trait_impl_conflict.rs index 0adedfd4ee..c3ecbb014d 100644 --- a/src/test/auxiliary/trait_impl_conflict.rs +++ b/src/test/auxiliary/trait_impl_conflict.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -pub trait Foo : ::std::marker::MarkerTrait { +pub trait Foo { } impl Foo for isize { diff --git a/src/test/auxiliary/typeck_default_trait_impl_cross_crate_coherence_lib.rs b/src/test/auxiliary/typeck_default_trait_impl_cross_crate_coherence_lib.rs index 5a7a3e7bcc..2e425ac96c 100644 --- a/src/test/auxiliary/typeck_default_trait_impl_cross_crate_coherence_lib.rs +++ b/src/test/auxiliary/typeck_default_trait_impl_cross_crate_coherence_lib.rs @@ -11,9 +11,7 @@ #![feature(optin_builtin_traits, core)] #![crate_type = "rlib"] -use std::marker::MarkerTrait; - -pub trait DefaultedTrait : MarkerTrait { } +pub trait DefaultedTrait { } impl DefaultedTrait for .. { } pub struct Something { t: T } diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 0cff90d61e..8f3e939f1f 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures, std_misc, rand)] +#![feature(std_misc, rand)] use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; -use std::rand::{Rng, IsaacRng, SeedableRng}; +use std::__rand::{Rng, thread_rng}; use std::time::Duration; fn timed(label: &str, f: F) where F: FnMut() { @@ -114,7 +114,7 @@ fn main() { { let seed: &[_] = &[1, 1, 1, 1, 1, 1, 1]; - let mut rng: IsaacRng = SeedableRng::from_seed(seed); + let mut rng = thread_rng(); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.gen(); diff --git a/src/test/bench/core-std.rs b/src/test/bench/core-std.rs index 0344d6a46e..46caed6f9f 100644 --- a/src/test/bench/core-std.rs +++ b/src/test/bench/core-std.rs @@ -11,18 +11,14 @@ // ignore-lexer-test FIXME #15679 // Microbenchmarks for various functions in std and extra -#![feature(unboxed_closures, rand, old_io, old_path, std_misc, collections)] +#![feature(rand, collections, std_misc)] -use std::old_io::*; -use std::old_path::{Path, GenericPath}; use std::iter::repeat; use std::mem::swap; use std::env; -use std::rand::Rng; -use std::rand; +use std::__rand::{thread_rng, Rng}; use std::str; use std::time::Duration; -use std::vec; fn main() { let argv: Vec = env::args().collect(); @@ -35,7 +31,6 @@ fn main() { } bench!(shift_push); - bench!(read_line); bench!(vec_plus); bench!(vec_append); bench!(vec_push_all); @@ -48,7 +43,7 @@ fn maybe_run_test(argv: &[String], name: String, test: F) where F: FnOnce() { if env::var_os("RUST_BENCH").is_some() { run_test = true - } else if argv.len() > 0 { + } else if !argv.is_empty() { run_test = argv.iter().any(|x| x == &"all".to_string()) || argv.iter().any(|x| x == &name) } @@ -65,26 +60,13 @@ fn shift_push() { let mut v1 = repeat(1).take(30000).collect::>(); let mut v2 = Vec::new(); - while v1.len() > 0 { + while !v1.is_empty() { v2.push(v1.remove(0)); } } -fn read_line() { - use std::old_io::BufferedReader; - - let mut path = Path::new(env!("CFG_SRC_DIR")); - path.push("src/test/bench/shootout-k-nucleotide.data"); - - for _ in 0..3 { - let mut reader = BufferedReader::new(File::open(&path).unwrap()); - for _line in reader.lines() { - } - } -} - fn vec_plus() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -102,7 +84,7 @@ fn vec_plus() { } fn vec_append() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); let mut i = 0; @@ -123,7 +105,7 @@ fn vec_append() { } fn vec_push_all() { - let mut r = rand::thread_rng(); + let mut r = thread_rng(); let mut v = Vec::new(); for i in 0..1500 { diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 83c39b3f3f..bcfdf23e70 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -15,8 +15,7 @@ #![feature(rand, core)] use std::f32::consts::PI; -use std::num::Float; -use std::rand::{Rng, StdRng}; +use std::__rand::{Rng, thread_rng}; #[derive(Copy, Clone)] struct Vec2 { @@ -44,7 +43,7 @@ struct Noise2DContext { impl Noise2DContext { fn new() -> Noise2DContext { - let mut rng = StdRng::new().unwrap(); + let mut rng = thread_rng(); let mut rgradients = [Vec2 { x: 0.0, y: 0.0 }; 256]; for x in &mut rgradients[..] { diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index ce050cc732..c576eea360 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -109,13 +109,12 @@ fn main() { let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth); let messages = (min_depth..max_depth + 1).step_by(2).map(|depth| { - use std::num::Int; - let iterations = 2.pow((max_depth - depth + min_depth) as u32); - thread::scoped(move || inner(depth, iterations)) + let iterations = 2i32.pow((max_depth - depth + min_depth) as u32); + thread::spawn(move || inner(depth, iterations)) }).collect::>(); for message in messages { - println!("{}", message.join()); + println!("{}", message.join().unwrap()); } println!("long lived tree of depth {}\t check: {}", diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 4489a124ab..32504350e4 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -166,7 +166,7 @@ fn fannkuch(n: i32) -> (i32, i32) { for (_, j) in (0..N).zip((0..).step_by(k)) { let max = cmp::min(j+k, perm.max()); - futures.push(thread::scoped(move|| { + futures.push(thread::spawn(move|| { work(perm, j as usize, max as usize) })) } @@ -174,7 +174,7 @@ fn fannkuch(n: i32) -> (i32, i32) { let mut checksum = 0; let mut maxflips = 0; for fut in futures { - let (cs, mf) = fut.join(); + let (cs, mf) = fut.join().unwrap(); checksum += cs; maxflips = cmp::max(maxflips, mf); } diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index effdd67027..145ab71446 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -38,13 +38,11 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(core, old_io, io, core)] - use std::cmp::min; -use std::old_io::*; -use std::iter::repeat; use std::env; -use std::slice::bytes::copy_memory; +use std::io; +use std::io::prelude::*; +use std::iter::repeat; const LINE_LEN: usize = 60; const LOOKUP_SIZE: usize = 4 * 1024; @@ -116,27 +114,31 @@ struct RepeatFasta<'a, W:'a> { out: &'a mut W } -impl<'a, W: Writer> RepeatFasta<'a, W> { +impl<'a, W: Write> RepeatFasta<'a, W> { fn new(alu: &'static str, w: &'a mut W) -> RepeatFasta<'a, W> { RepeatFasta { alu: alu, out: w } } - fn make(&mut self, n: usize) -> IoResult<()> { + fn make(&mut self, n: usize) -> io::Result<()> { let alu_len = self.alu.len(); let mut buf = repeat(0).take(alu_len + LINE_LEN).collect::>(); let alu: &[u8] = self.alu.as_bytes(); - copy_memory(alu, &mut buf); + for (slot, val) in buf.iter_mut().zip(alu.iter()) { + *slot = *val; + } let buf_len = buf.len(); - copy_memory(&alu[..LINE_LEN], &mut buf[alu_len..buf_len]); + for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(alu[..LINE_LEN].iter()) { + *slot = *val; + } let mut pos = 0; let mut bytes; let mut n = n; while n > 0 { bytes = min(LINE_LEN, n); - try!(self.out.write(&buf[pos..pos + bytes])); - try!(self.out.write_u8('\n' as u8)); + try!(self.out.write_all(&buf[pos..pos + bytes])); + try!(self.out.write_all(&[b'\n'])); pos += bytes; if pos > alu_len { pos -= alu_len; @@ -165,7 +167,7 @@ struct RandomFasta<'a, W:'a> { out: &'a mut W, } -impl<'a, W: Writer> RandomFasta<'a, W> { +impl<'a, W: Write> RandomFasta<'a, W> { fn new(w: &'a mut W, a: &[AminoAcid]) -> RandomFasta<'a, W> { RandomFasta { seed: 42, @@ -189,7 +191,7 @@ impl<'a, W: Writer> RandomFasta<'a, W> { 0 } - fn make(&mut self, n: usize) -> IoResult<()> { + fn make(&mut self, n: usize) -> io::Result<()> { let lines = n / LINE_LEN; let chars_left = n % LINE_LEN; let mut buf = [0;LINE_LEN + 1]; @@ -204,7 +206,7 @@ impl<'a, W: Writer> RandomFasta<'a, W> { for i in 0..chars_left { buf[i] = self.nextc(); } - self.out.write(&buf[..chars_left]) + self.out.write_all(&buf[..chars_left]) } } @@ -216,23 +218,23 @@ fn main() { 5 }; - let mut out = stdout(); + let mut out = io::stdout(); - out.write_line(">ONE Homo sapiens alu").unwrap(); + out.write_all(b">ONE Homo sapiens alu\n").unwrap(); { let mut repeat = RepeatFasta::new(ALU, &mut out); repeat.make(n * 2).unwrap(); } - out.write_line(">TWO IUB ambiguity codes").unwrap(); + out.write_all(b">TWO IUB ambiguity codes\n").unwrap(); let iub = sum_and_scale(&IUB); let mut random = RandomFasta::new(&mut out, &iub); random.make(n * 3).unwrap(); - random.out.write_line(">THREE Homo sapiens frequency").unwrap(); + random.out.write_all(b">THREE Homo sapiens frequency\n").unwrap(); let homo_sapiens = sum_and_scale(&HOMO_SAPIENS); random.lookup = make_lookup(&homo_sapiens); random.make(n * 5).unwrap(); - random.out.write_str("\n").unwrap(); + random.out.write_all(b"\n").unwrap(); } diff --git a/src/test/bench/shootout-fasta.rs b/src/test/bench/shootout-fasta.rs index 78d31faeb5..accf525b4e 100644 --- a/src/test/bench/shootout-fasta.rs +++ b/src/test/bench/shootout-fasta.rs @@ -38,14 +38,11 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(old_io, old_path, io, core)] - use std::cmp::min; -use std::old_io::*; -use std::old_io; -use std::old_path::Path; -use std::num::Float; use std::env; +use std::fs::File; +use std::io::{self, BufWriter}; +use std::io::prelude::*; const LINE_LENGTH: usize = 60; const IM: u32 = 139968; @@ -87,9 +84,9 @@ impl<'a> Iterator for AAGen<'a> { } } -fn make_fasta>( +fn make_fasta>( wr: &mut W, header: &str, mut it: I, mut n: usize) - -> std::old_io::IoResult<()> + -> io::Result<()> { try!(wr.write(header.as_bytes())); let mut line = [0; LINE_LENGTH + 1]; @@ -105,7 +102,7 @@ fn make_fasta>( Ok(()) } -fn run(writer: &mut W) -> std::old_io::IoResult<()> { +fn run(writer: &mut W) -> io::Result<()> { let mut args = env::args(); let n = if env::var_os("RUST_BENCH").is_some() { 25000000 @@ -146,10 +143,10 @@ fn run(writer: &mut W) -> std::old_io::IoResult<()> { fn main() { let res = if env::var_os("RUST_BENCH").is_some() { - let mut file = BufferedWriter::new(File::create(&Path::new("./shootout-fasta.data"))); + let mut file = BufWriter::new(File::create("./shootout-fasta.data").unwrap()); run(&mut file) } else { - run(&mut old_io::stdout()) + run(&mut io::stdout()) }; res.unwrap() } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index c190641bfb..b777b25243 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -13,18 +13,17 @@ // multi tasking k-nucleotide -#![feature(box_syntax, std_misc, old_io, collections, os)] +#![allow(bad_style)] -use std::ascii::{AsciiExt, OwnedAsciiExt}; +use std::ascii::AsciiExt; use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::collections::HashMap; use std::mem::replace; -use std::num::Float; -use std::option; -use std::os; use std::env; use std::sync::mpsc::{channel, Sender, Receiver}; use std::thread; +use std::io; +use std::io::prelude::*; fn f64_cmp(x: f64, y: f64) -> Ordering { // arbitrarily decide that NaNs are larger than everything. @@ -75,10 +74,10 @@ fn sort_and_fmt(mm: &HashMap , usize>, total: usize) -> String { // given a map, search for the frequency of a pattern fn find(mm: &HashMap , usize>, key: String) -> usize { - let key = key.into_ascii_lowercase(); + let key = key.to_ascii_lowercase(); match mm.get(key.as_bytes()) { - option::Option::None => { return 0; } - option::Option::Some(&num) => { return num; } + None => 0, + Some(&num) => num, } } @@ -123,7 +122,7 @@ fn make_sequence_processor(sz: usize, line = from_parent.recv().unwrap(); if line == Vec::new() { break; } - carry.push_all(&line); + carry.extend(line); carry = windows_with_carry(&carry, sz, |window| { update_freq(&mut freqs, window); total += 1; @@ -147,15 +146,13 @@ fn make_sequence_processor(sz: usize, // given a FASTA file on stdin, process sequence THREE fn main() { - use std::old_io::*; - + let input = io::stdin(); let rdr = if env::var_os("RUST_BENCH").is_some() { - let foo = include_bytes!("shootout-k-nucleotide.data"); - box MemReader::new(foo.to_vec()) as Box + let foo: &[u8] = include_bytes!("shootout-k-nucleotide.data"); + Box::new(foo) as Box } else { - box stdio::stdin() as Box + Box::new(input.lock()) as Box }; - let mut rdr = BufferedReader::new(rdr); // initialize each sequence sorter let sizes: Vec = vec!(1,2,3,4,6,12,18); @@ -187,7 +184,7 @@ fn main() { for line in rdr.lines() { let line = line.unwrap().trim().to_string(); - if line.len() == 0 { continue; } + if line.is_empty() { continue; } match (line.as_bytes()[0] as char, proc_mode) { diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index db131bcfdc..c4af33da50 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -252,7 +252,7 @@ fn generate_frequencies(mut input: &[u8], frame: usize) -> Table { } frequencies.lookup(code, BumpCallback); - while input.len() != 0 && input[0] != ('>' as u8) { + while !input.is_empty() && input[0] != ('>' as u8) { code = code.rotate(input[0], frame); frequencies.lookup(code, BumpCallback); input = &input[1..]; @@ -307,17 +307,17 @@ fn main() { let nb_freqs: Vec<_> = (1..3).map(|i| { let input = input.clone(); - (i, thread::scoped(move|| generate_frequencies(&input, i))) + (i, thread::spawn(move|| generate_frequencies(&input, i))) }).collect(); let occ_freqs: Vec<_> = OCCURRENCES.iter().map(|&occ| { let input = input.clone(); - thread::scoped(move|| generate_frequencies(&input, occ.len())) + thread::spawn(move|| generate_frequencies(&input, occ.len())) }).collect(); for (i, freq) in nb_freqs { - print_frequencies(&freq.join(), i); + print_frequencies(&freq.join().unwrap(), i); } for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs.into_iter()) { - print_occurrences(&mut freq.join(), occ); + print_occurrences(&mut freq.join().unwrap(), occ); } } diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index d248293103..f2714d55e5 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -38,13 +38,13 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(simd, old_io, core, io)] +#![feature(simd, core)] // ignore-pretty very bad with line comments -use std::old_io; -use std::old_io::*; use std::env; +use std::io::prelude::*; +use std::io; use std::simd::f64x2; use std::sync::Arc; use std::thread; @@ -53,8 +53,7 @@ const ITER: usize = 50; const LIMIT: f64 = 2.0; const WORKERS: usize = 16; -#[inline(always)] -fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { +fn mandelbrot(w: usize, mut out: W) -> io::Result<()> { assert!(WORKERS % 2 == 0); // Ensure w and h are multiples of 8. @@ -82,7 +81,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let mut precalc_i = Vec::with_capacity(h); let precalc_futures = (0..WORKERS).map(|i| { - thread::scoped(move|| { + thread::spawn(move|| { let mut rs = Vec::with_capacity(w / WORKERS); let mut is = Vec::with_capacity(w / WORKERS); @@ -108,7 +107,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { }).collect::>(); for res in precalc_futures { - let (rs, is) = res.join(); + let (rs, is) = res.join().unwrap(); precalc_r.extend(rs.into_iter()); precalc_i.extend(is.into_iter()); } @@ -123,7 +122,7 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { let vec_init_r = arc_init_r.clone(); let vec_init_i = arc_init_i.clone(); - thread::scoped(move|| { + thread::spawn(move|| { let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); let init_r_slice = vec_init_r; @@ -142,9 +141,9 @@ fn mandelbrot(w: usize, mut out: W) -> old_io::IoResult<()> { }) }).collect::>(); - try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h)); + try!(writeln!(&mut out, "P4\n{} {}", w, h)); for res in data { - try!(out.write(&res.join())); + try!(out.write_all(&res.join().unwrap())); } out.flush() } @@ -202,9 +201,9 @@ fn main() { let res = if args.len() < 2 { println!("Test mode: do not dump the image because it's not utf8, \ which interferes with the test runner."); - mandelbrot(1000, old_io::util::NullWriter) + mandelbrot(1000, io::sink()) } else { - mandelbrot(args.nth(1).unwrap().parse().unwrap(), old_io::stdout()) + mandelbrot(args.nth(1).unwrap().parse().unwrap(), io::stdout()) }; res.unwrap(); } diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 669a0e86f1..368dbbb931 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -38,9 +38,7 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED // OF THE POSSIBILITY OF SUCH DAMAGE. -#![feature(core)] - -use std::num::Float; +use std::mem; const PI: f64 = 3.141592653589793; const SOLAR_MASS: f64 = 4.0 * PI * PI; @@ -193,16 +191,9 @@ fn main() { /// longer contain the mutable reference. This is a safe operation because the /// two mutable borrows are entirely disjoint. fn shift_mut_ref<'a, T>(r: &mut &'a mut [T]) -> Option<&'a mut T> { - use std::mem; - use std::raw::Repr; - - if r.len() == 0 { return None } - unsafe { - let mut raw = r.repr(); - let ret = raw.data as *mut T; - raw.data = raw.data.offset(1); - raw.len -= 1; - *r = mem::transmute(raw); - Some({ &mut *ret }) - } + let res = mem::replace(r, &mut []); + if res.is_empty() { return None } + let (a, b) = res.split_at_mut(1); + *r = b; + Some(&mut a[0]) } diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index cda90c08f2..7c9f33678a 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -40,18 +40,18 @@ // ignore-android see #10393 #13206 -#![feature(unboxed_closures, libc, old_io, collections, io, core)] +#![feature(libc, scoped)] extern crate libc; -use std::old_io::stdio::{stdin_raw, stdout_raw}; -use std::old_io::*; -use std::ptr::{copy, Unique}; +use std::io; +use std::io::prelude::*; +use std::ptr::copy; use std::thread; struct Tables { - table8: [u8;1 << 8], - table16: [u16;1 << 16] + table8: [u8; 1 << 8], + table16: [u16; 1 << 16] } impl Tables { @@ -101,36 +101,6 @@ impl Tables { } } -/// Reads all remaining bytes from the stream. -fn read_to_end(r: &mut R) -> IoResult> { - // As reading the input stream in memory is a bottleneck, we tune - // Reader::read_to_end() with a fast growing policy to limit - // recopies. If MREMAP_RETAIN is implemented in the linux kernel - // and jemalloc use it, this trick will become useless. - const CHUNK: usize = 64 * 1024; - - let mut vec = Vec::with_capacity(CHUNK); - loop { - // workaround: very fast growing - let len = vec.len(); - if vec.capacity() - len < CHUNK { - let cap = vec.capacity(); - let mult = if cap < 256 * 1024 * 1024 { - 16 - } else { - 2 - }; - vec.reserve_exact(mult * cap - len); - } - match r.push_at_least(1, CHUNK, &mut vec) { - Ok(_) => {} - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => return Err(e) - } - } - Ok(vec) -} - /// Finds the first position at which `b` occurs in `s`. fn memchr(h: &[u8], n: u8) -> Option { use libc::{c_void, c_int, size_t}; @@ -175,7 +145,8 @@ const LINE_LEN: usize = 60; /// Compute the reverse complement. fn reverse_complement(seq: &mut [u8], tables: &Tables) { - let seq = seq.init_mut();// Drop the last newline + let len = seq.len(); + let seq = &mut seq[..len - 1]; // Drop the last newline let len = seq.len(); let off = LINE_LEN - len % (LINE_LEN + 1); let mut i = LINE_LEN; @@ -222,26 +193,20 @@ fn reverse_complement(seq: &mut [u8], tables: &Tables) { } } - -struct Racy(T); - -unsafe impl Send for Racy {} - /// Executes a closure in parallel over the given iterator over mutable slice. /// The closure `f` is run in parallel with an element of `iter`. -fn parallel<'a, I: Iterator, F>(iter: I, ref f: F) - where I::Item: Send + 'a, - F: Fn(I::Item) + Sync + 'a { +fn parallel(iter: I, ref f: F) + where I::Item: Send, + F: Fn(I::Item) + Sync, { iter.map(|x| { - thread::scoped(move|| { - f(x) - }) + thread::scoped(move || f(x)) }).collect::>(); } fn main() { - let mut data = read_to_end(&mut stdin_raw()).unwrap(); + let mut data = Vec::with_capacity(1024 * 1024); + io::stdin().read_to_end(&mut data); let tables = &Tables::new(); parallel(mut_dna_seqs(&mut data), |seq| reverse_complement(seq, tables)); - stdout_raw().write(&data).unwrap(); + io::stdout().write_all(&data).unwrap(); } diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index c0268e816c..0fa22abde3 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -41,12 +41,11 @@ // no-pretty-expanded FIXME #15189 #![allow(non_snake_case)] -#![feature(unboxed_closures, core, os)] +#![feature(unboxed_closures, core, os, scoped)] -use std::iter::{repeat, AdditiveIterator}; +use std::iter::repeat; use std::thread; use std::mem; -use std::num::Float; use std::os; use std::env; use std::raw::Repr; diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 3913de3a3f..16742f0a6e 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -16,7 +16,6 @@ use std::io::prelude::*; use std::io; use std::iter::repeat; -use std::num::Int; use std::env; // Computes a single solution to a given 9x9 sudoku diff --git a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs index a88445bafc..022a6b4f2f 100644 --- a/src/test/compile-fail-fulldeps/gated-macro-reexports.rs +++ b/src/test/compile-fail-fulldeps/gated-macro-reexports.rs @@ -19,4 +19,3 @@ #[macro_use] #[no_link] extern crate macro_reexport_1; //~^ ERROR macros reexports are experimental and possibly buggy -//~| HELP add #![feature(macro_reexport)] to the crate attributes to enable diff --git a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs index c55e24e81a..2b34fcab24 100644 --- a/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs +++ b/src/test/compile-fail/associated-type-projection-from-multiple-supertraits.rs @@ -34,6 +34,9 @@ fn dent(c: C, color: C::Color) { fn dent_object(c: BoxCar) { //~^ ERROR ambiguous associated type + //~| ERROR the value of the associated type `Color` (from the trait `Vehicle`) must be specified + //~| NOTE could derive from `Vehicle` + //~| NOTE could derive from `Box` } fn paint(c: C, d: C::Color) { diff --git a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs index 04170779ed..0e083e4723 100644 --- a/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs +++ b/src/test/compile-fail/associated-types-ICE-when-projecting-out-of-err.rs @@ -16,12 +16,8 @@ #![feature(no_std)] #![no_std] -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } - #[lang="sized"] -pub trait Sized : PhantomFn { +pub trait Sized { // Empty. } diff --git a/src/test/compile-fail/associated-types-eq-expr-path.rs b/src/test/compile-fail/associated-types-eq-expr-path.rs index 0d68b960f3..1f9dfdb184 100644 --- a/src/test/compile-fail/associated-types-eq-expr-path.rs +++ b/src/test/compile-fail/associated-types-eq-expr-path.rs @@ -10,7 +10,7 @@ // Check that an associated type cannot be bound in an expression path. -trait Foo : ::std::marker::MarkerTrait { +trait Foo { type A; fn bar() -> isize; } diff --git a/src/test/compile-fail/associated-types-issue-17359.rs b/src/test/compile-fail/associated-types-issue-17359.rs index 5c36e3356a..82258f124d 100644 --- a/src/test/compile-fail/associated-types-issue-17359.rs +++ b/src/test/compile-fail/associated-types-issue-17359.rs @@ -11,7 +11,7 @@ // Test that we do not ICE when an impl is missing an associated type (and that we report // a useful error, of course). -trait Trait : ::std::marker::MarkerTrait { +trait Trait { type Type; } diff --git a/src/test/compile-fail/associated-types-multiple-types-one-trait.rs b/src/test/compile-fail/associated-types-multiple-types-one-trait.rs index 5632f148da..9436f825de 100644 --- a/src/test/compile-fail/associated-types-multiple-types-one-trait.rs +++ b/src/test/compile-fail/associated-types-multiple-types-one-trait.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo : ::std::marker::MarkerTrait { +trait Foo { type X; type Y; } diff --git a/src/test/compile-fail/associated-types-no-suitable-supertrait-2.rs b/src/test/compile-fail/associated-types-no-suitable-supertrait-2.rs new file mode 100644 index 0000000000..bda16c8a85 --- /dev/null +++ b/src/test/compile-fail/associated-types-no-suitable-supertrait-2.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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. + +// Check that we get an error when you use `::Value` in +// the trait definition but `Self` does not, in fact, implement `Get`. +// +// See also associated-types-no-suitable-supertrait.rs, which checks +// that we see the same error when making this mistake on an impl +// rather than the default method impl. +// +// See also run-pass/associated-types-projection-to-unrelated-trait.rs, +// which checks that the trait interface itself is not considered an +// error as long as all impls satisfy the constraint. + +trait Get { + type Value; +} + +trait Other { + fn uhoh(&self, foo: U, bar: ::Value) {} + //~^ ERROR the trait `Get` is not implemented for the type `Self` +} + +fn main() { } diff --git a/src/test/compile-fail/associated-types-no-suitable-supertrait.rs b/src/test/compile-fail/associated-types-no-suitable-supertrait.rs index 2b84c38f80..233532a608 100644 --- a/src/test/compile-fail/associated-types-no-suitable-supertrait.rs +++ b/src/test/compile-fail/associated-types-no-suitable-supertrait.rs @@ -10,20 +10,30 @@ // Check that we get an error when you use `::Value` in // the trait definition but `Self` does not, in fact, implement `Get`. +// +// See also associated-types-no-suitable-supertrait-2.rs, which checks +// that we see the same error if we get around to checking the default +// method body. +// +// See also run-pass/associated-types-projection-to-unrelated-trait.rs, +// which checks that the trait interface itself is not considered an +// error as long as all impls satisfy the constraint. -trait Get : ::std::marker::MarkerTrait { +trait Get { type Value; } trait Other { fn uhoh(&self, foo: U, bar: ::Value) {} - //~^ ERROR the trait `Get` is not implemented for the type `Self` + // (note that we no longer catch the error here, since the + // error below aborts compilation. + // See also associated-types-no-suitable-supertrait-2.rs + // which checks that this error would be caught eventually.) } impl Other for T { fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} //~^ ERROR the trait `Get` is not implemented for the type `(T, U)` - //~| ERROR the trait `Get` is not implemented for the type `(T, U)` } fn main() { } diff --git a/src/test/compile-fail/associated-types-unconstrained.rs b/src/test/compile-fail/associated-types-unconstrained.rs index 8832028f9a..aecbf217a5 100644 --- a/src/test/compile-fail/associated-types-unconstrained.rs +++ b/src/test/compile-fail/associated-types-unconstrained.rs @@ -10,7 +10,7 @@ // Check that an associated type cannot be bound in an expression path. -trait Foo : ::std::marker::MarkerTrait { +trait Foo { type A; fn bar() -> isize; } diff --git a/src/test/compile-fail/bad-mid-path-type-params.rs b/src/test/compile-fail/bad-mid-path-type-params.rs index 7a7406115d..20ac757354 100644 --- a/src/test/compile-fail/bad-mid-path-type-params.rs +++ b/src/test/compile-fail/bad-mid-path-type-params.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - struct S { contents: T, } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 1944acbe1f..fca74e457c 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - use std::cell::RefCell; -trait Trait : ::std::marker::MarkerTrait {} +trait Trait {} pub fn main() { let x: Vec = Vec::new(); diff --git a/src/test/compile-fail/borrowck-escaping-closure-error-1.rs b/src/test/compile-fail/borrowck-escaping-closure-error-1.rs new file mode 100644 index 0000000000..87e40df766 --- /dev/null +++ b/src/test/compile-fail/borrowck-escaping-closure-error-1.rs @@ -0,0 +1,25 @@ +// 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 std::thread::spawn; + +// Test that we give a custom error (E0373) for the case where a +// closure is escaping current frame, and offer a suggested code edit. +// I refrained from including the precise message here, but the +// original text as of the time of this writing is: +// +// closure may outlive the current function, but it borrows `books`, +// which is owned by the current function + +fn main() { + let mut books = vec![1,2,3]; + spawn(|| books.push(4)); + //~^ ERROR E0373 +} diff --git a/src/test/compile-fail/borrowck-escaping-closure-error-2.rs b/src/test/compile-fail/borrowck-escaping-closure-error-2.rs new file mode 100644 index 0000000000..67700be890 --- /dev/null +++ b/src/test/compile-fail/borrowck-escaping-closure-error-2.rs @@ -0,0 +1,25 @@ +// 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. + +// Test that we give a custom error (E0373) for the case where a +// closure is escaping current frame, and offer a suggested code edit. +// I refrained from including the precise message here, but the +// original text as of the time of this writing is: +// +// closure may outlive the current function, but it borrows `books`, +// which is owned by the current function + +fn foo<'a>(x: &'a i32) -> Box { + let mut books = vec![1,2,3]; + Box::new(|| books.push(4)) + //~^ ERROR E0373 +} + +fn main() { } diff --git a/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs b/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs new file mode 100644 index 0000000000..796b455f5c --- /dev/null +++ b/src/test/compile-fail/borrowck-use-uninitialized-in-cast-trait.rs @@ -0,0 +1,20 @@ +// 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. + +// Variation on `borrowck-use-uninitialized-in-cast` in which we do a +// trait cast from an uninitialized source. Issue #20791. + +trait Foo { fn dummy(&self) { } } +impl Foo for i32 { } + +fn main() { + let x: &i32; + let y = x as *const Foo; //~ ERROR use of possibly uninitialized variable: `*x` +} diff --git a/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs b/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs new file mode 100644 index 0000000000..a3d5af80b5 --- /dev/null +++ b/src/test/compile-fail/borrowck-use-uninitialized-in-cast.rs @@ -0,0 +1,20 @@ +// 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. + +// Check that we detect unused values that are cast to other things. +// The problem was specified to casting to `*`, as creating unsafe +// pointers was not being fully checked. Issue #20791. + +// pretty-expanded FIXME #23616 + +fn main() { + let x: &i32; + let y = x as *const i32; //~ ERROR use of possibly uninitialized variable: `*x` +} diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs index 98a9c713e8..b771b959d3 100644 --- a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs +++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-implemented.rs @@ -10,7 +10,6 @@ use std::fmt::Debug; use std::default::Default; -use std::marker::MarkerTrait; // Test that two blanket impls conflict (at least without negative // bounds). After all, some other crate could implement Even or Odd @@ -20,9 +19,9 @@ trait MyTrait { fn get(&self) -> usize; } -trait Even : MarkerTrait { } +trait Even { } -trait Odd : MarkerTrait { } +trait Odd { } impl Even for isize { } diff --git a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs index 57d25a3bf5..d3b0e7f10b 100644 --- a/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs +++ b/src/test/compile-fail/coherence-blanket-conflicts-with-blanket-unimplemented.rs @@ -19,9 +19,9 @@ trait MyTrait { fn get(&self) -> usize; } -trait Even : ::std::marker::MarkerTrait { } +trait Even {} -trait Odd : ::std::marker::MarkerTrait { } +trait Odd {} impl MyTrait for T { //~ ERROR E0119 fn get(&self) -> usize { 0 } diff --git a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs index a225f6cf47..55c9ba2a0e 100644 --- a/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs +++ b/src/test/compile-fail/coherence-conflicting-negative-trait-impl.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait MyTrait : ::std::marker::MarkerTrait {} +trait MyTrait {} struct TestType(::std::marker::PhantomData); diff --git a/src/test/compile-fail/coherence-default-trait-impl.rs b/src/test/compile-fail/coherence-default-trait-impl.rs index a5b3173073..cccc8b05b3 100644 --- a/src/test/compile-fail/coherence-default-trait-impl.rs +++ b/src/test/compile-fail/coherence-default-trait-impl.rs @@ -8,25 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait {} +trait MyTrait {} impl MyTrait for .. {} impl MyTrait for .. {} //~^ ERROR conflicting implementations for trait `MyTrait` -trait MySafeTrait: MarkerTrait {} +trait MySafeTrait {} unsafe impl MySafeTrait for .. {} //~^ ERROR implementing the trait `MySafeTrait` is not unsafe -unsafe trait MyUnsafeTrait: MarkerTrait {} +unsafe trait MyUnsafeTrait {} impl MyUnsafeTrait for .. {} //~^ ERROR the trait `MyUnsafeTrait` requires an `unsafe impl` declaration diff --git a/src/test/compile-fail/coherence-impl-trait-for-trait.rs b/src/test/compile-fail/coherence-impl-trait-for-trait.rs new file mode 100644 index 0000000000..23f4218fc1 --- /dev/null +++ b/src/test/compile-fail/coherence-impl-trait-for-trait.rs @@ -0,0 +1,32 @@ +// 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. + +// Test that we give suitable error messages when the user attempts to +// impl a trait `Trait` for its own object type. + +trait Foo { fn dummy(&self) { } } +trait Bar: Foo { } +trait Baz: Bar { } + +// Subtraits of Baz are not legal: +impl Foo for Baz { } //~ ERROR E0371 +impl Bar for Baz { } //~ ERROR E0371 +impl Baz for Baz { } //~ ERROR E0371 + +// But other random traits are: +trait Other { } +impl Other for Baz { } // OK, Bar not a subtrait of Baz + +// If the trait is not object-safe, we give a more tailored message +// because we're such schnuckels: +trait NotObjectSafe { fn eq(&self, other: Self); } +impl NotObjectSafe for NotObjectSafe { } //~ ERROR E0372 + +fn main() { } diff --git a/src/test/compile-fail/coherence-orphan.rs b/src/test/compile-fail/coherence-orphan.rs index 2243a0507f..78435f1a78 100644 --- a/src/test/compile-fail/coherence-orphan.rs +++ b/src/test/compile-fail/coherence-orphan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength // aux-build:coherence_orphan_lib.rs #![feature(optin_builtin_traits)] diff --git a/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs new file mode 100644 index 0000000000..3fd635b3d6 --- /dev/null +++ b/src/test/compile-fail/coherence-overlap-all-t-and-tuple.rs @@ -0,0 +1,28 @@ +// 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. + +// Check that we detect an overlap here in the case where: +// +// for some type X: +// T = (X,) +// T11 = X, U11 = X +// +// Seems pretty basic, but then there was issue #24241. :) + +trait From { +} + +impl From for T { //~ ERROR E0119 +} + +impl From<(U11,)> for (T11,) { +} + +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs index f13175ce8e..fcd6e5c495 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -18,11 +18,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs index ae3d242af7..b5c0a7fb5f 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -18,11 +18,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } // `MyFundamentalStruct` is declared fundamental, so we can test that diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs index c4e95e7723..a6b62d17bc 100644 --- a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -17,11 +17,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } //~ ERROR E0119 diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs index f768a475ee..5a9f440f8b 100644 --- a/src/test/compile-fail/coherence_copy_like_err_struct.rs +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -15,11 +15,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } //~ ERROR E0119 // `MyStruct` is not declared fundamental, therefore this would diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs index 0c78fffd2d..ee0d5550fd 100644 --- a/src/test/compile-fail/coherence_copy_like_err_tuple.rs +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -15,11 +15,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } //~ ERROR E0119 // Tuples are not fundamental, therefore this would require that diff --git a/src/test/compile-fail/derive-no-std-not-supported.rs b/src/test/compile-fail/derive-no-std-not-supported.rs index d0cb4f23a8..327e2c9e0f 100644 --- a/src/test/compile-fail/derive-no-std-not-supported.rs +++ b/src/test/compile-fail/derive-no-std-not-supported.rs @@ -15,12 +15,6 @@ extern crate core; extern crate rand; extern crate serialize as rustc_serialize; -#[derive(Rand)] //~ ERROR this trait cannot be derived -//~^ WARNING `#[derive(Rand)]` is deprecated -struct Foo { - x: u32, -} - #[derive(RustcEncodable)] //~ ERROR this trait cannot be derived struct Bar { x: u32, diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs index aa687266ac..160197368d 100644 --- a/src/test/compile-fail/dst-bad-coerce2.rs +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -15,7 +15,7 @@ struct Fat { } struct Foo; -trait Bar : ::std::marker::MarkerTrait {} +trait Bar {} impl Bar for Foo {} pub fn main() { diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs index 8ec1034bc4..b30eada162 100644 --- a/src/test/compile-fail/dst-bad-coercions.rs +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -10,10 +10,8 @@ // Test implicit coercions involving DSTs and raw pointers. -use std::marker::MarkerTrait; - struct S; -trait T : MarkerTrait {} +trait T {} impl T for S {} struct Foo { diff --git a/src/test/compile-fail/dupe-symbols-1.rs b/src/test/compile-fail/dupe-symbols-1.rs new file mode 100644 index 0000000000..9fa4eafcad --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-1.rs @@ -0,0 +1,21 @@ +// 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-2.rs b/src/test/compile-fail/dupe-symbols-2.rs new file mode 100644 index 0000000000..976a65589b --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -0,0 +1,25 @@ +// 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +mod a { + #[no_mangle] + pub extern fn fail() { + } +} + +mod b { + #[no_mangle] + pub extern fn fail() { + //~^ symbol `fail` is already defined + } +} diff --git a/src/test/compile-fail/dupe-symbols-3.rs b/src/test/compile-fail/dupe-symbols-3.rs new file mode 100644 index 0000000000..98a61c33c5 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-3.rs @@ -0,0 +1,21 @@ +// 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[no_mangle] +pub fn fail() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-4.rs b/src/test/compile-fail/dupe-symbols-4.rs new file mode 100644 index 0000000000..9e730699d2 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -0,0 +1,31 @@ +// 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. +// +// error-pattern: symbol `fail` is already defined +#![crate_type="rlib"] +#![allow(warnings)] + + +pub trait A { + fn fail(self); +} + +struct B; +struct C; + +impl A for B { + #[no_mangle] + fn fail(self) {} +} + +impl A for C { + #[no_mangle] + fn fail(self) {} +} diff --git a/src/test/compile-fail/dupe-symbols-5.rs b/src/test/compile-fail/dupe-symbols-5.rs new file mode 100644 index 0000000000..eb4b50d03c --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-5.rs @@ -0,0 +1,20 @@ +// 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. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-6.rs b/src/test/compile-fail/dupe-symbols-6.rs new file mode 100644 index 0000000000..6f412d9a0d --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-6.rs @@ -0,0 +1,18 @@ +// 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. +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +static HELLO_TWICE: u16 = 0; +//~^ symbol `fail` is already defined diff --git a/src/test/compile-fail/dupe-symbols-7.rs b/src/test/compile-fail/dupe-symbols-7.rs new file mode 100644 index 0000000000..c2880ba6f5 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-7.rs @@ -0,0 +1,15 @@ +// 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. +// +// error-pattern: entry symbol `main` defined multiple times +#![allow(warnings)] + +#[no_mangle] +fn main(){} diff --git a/src/test/compile-fail/enum-to-float-cast-2.rs b/src/test/compile-fail/enum-to-float-cast-2.rs new file mode 100644 index 0000000000..7ee6713175 --- /dev/null +++ b/src/test/compile-fail/enum-to-float-cast-2.rs @@ -0,0 +1,28 @@ +// Copyright 2012 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. + +// Tests that enum-to-float casts are disallowed. + +enum E { + L0 = -1, + H0 = 1 +} + +enum F { + L1 = 1, + H1 = 0xFFFFFFFFFFFFFFFF +} + +pub fn main() { + let a = E::L0 as f32; //~ ERROR illegal cast + let c = F::H1 as f32; //~ ERROR illegal cast + assert_eq!(a, -1.0f32); + assert_eq!(c, -1.0f32); +} diff --git a/src/test/compile-fail/enum-to-float-cast.rs b/src/test/compile-fail/enum-to-float-cast.rs index 3ad2790655..225b870230 100644 --- a/src/test/compile-fail/enum-to-float-cast.rs +++ b/src/test/compile-fail/enum-to-float-cast.rs @@ -24,12 +24,8 @@ static C0: f32 = E::L0 as f32; //~ ERROR illegal cast static C1: f32 = F::H1 as f32; //~ ERROR illegal cast pub fn main() { - let a = E::L0 as f32; //~ ERROR illegal cast let b = C0; - let c = F::H1 as f32; //~ ERROR illegal cast let d = C1; - assert_eq!(a, -1.0f32); assert_eq!(b, -1.0f32); - assert_eq!(c, -1.0f32); assert_eq!(d, -1.0f32); } diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs new file mode 100644 index 0000000000..ac5969410f --- /dev/null +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -0,0 +1,19 @@ +// 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. + +fn main() { + let a: &[i32] = &[1, 2, 3]; + let b: Box<[i32]> = Box::new([1, 2, 3]); + let p = a as *const [i32]; + + a as usize; //~ ERROR cast from fat pointer + b as usize; //~ ERROR cast from fat pointer + p as usize; //~ ERROR cast from fat pointer +} diff --git a/src/test/compile-fail/gated-box-patterns.rs b/src/test/compile-fail/gated-box-patterns.rs index abaa256d52..d82d0dec72 100644 --- a/src/test/compile-fail/gated-box-patterns.rs +++ b/src/test/compile-fail/gated-box-patterns.rs @@ -16,7 +16,6 @@ fn main() { match x { box 1 => (), //~^ box pattern syntax is experimental - //~| add #![feature(box_patterns)] to the crate attributes to enable _ => () }; } diff --git a/src/test/compile-fail/gated-box-syntax.rs b/src/test/compile-fail/gated-box-syntax.rs index 3e08c1f7a7..a2643fe02b 100644 --- a/src/test/compile-fail/gated-box-syntax.rs +++ b/src/test/compile-fail/gated-box-syntax.rs @@ -13,5 +13,4 @@ fn main() { let x = box 3; //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead. - //~| HELP add #![feature(box_syntax)] to the crate attributes to enable } diff --git a/src/test/compile-fail/gated-link-args.rs b/src/test/compile-fail/gated-link-args.rs index c8845ced2f..7b1405c913 100644 --- a/src/test/compile-fail/gated-link-args.rs +++ b/src/test/compile-fail/gated-link-args.rs @@ -14,6 +14,5 @@ #[link_args = "aFdEfSeVEEE"] extern {} //~^ ERROR the `link_args` attribute is not portable across platforms -//~| HELP add #![feature(link_args)] to the crate attributes to enable fn main() { } diff --git a/src/test/compile-fail/gated-link-llvm-intrinsics.rs b/src/test/compile-fail/gated-link-llvm-intrinsics.rs index 716ea9f8db..92a1b07143 100644 --- a/src/test/compile-fail/gated-link-llvm-intrinsics.rs +++ b/src/test/compile-fail/gated-link-llvm-intrinsics.rs @@ -12,7 +12,6 @@ extern { #[link_name = "llvm.sqrt.f32"] fn sqrt(x: f32) -> f32; //~^ ERROR linking to LLVM intrinsics is experimental - //~| HELP add #![feature(link_llvm_intrinsics)] to the crate attributes } fn main(){ diff --git a/src/test/compile-fail/gated-plugin_registrar.rs b/src/test/compile-fail/gated-plugin_registrar.rs index d716c53e1d..9cdebde7b7 100644 --- a/src/test/compile-fail/gated-plugin_registrar.rs +++ b/src/test/compile-fail/gated-plugin_registrar.rs @@ -15,5 +15,4 @@ #[plugin_registrar] pub fn registrar() {} //~^ ERROR compiler plugins are experimental -//~| HELP add #![feature(plugin_registrar)] to the crate attributes to enable fn main() {} diff --git a/src/test/compile-fail/gated-unsafe-destructor.rs b/src/test/compile-fail/gated-unsafe-destructor.rs index 2aebbf3d54..9dd1e229e0 100644 --- a/src/test/compile-fail/gated-unsafe-destructor.rs +++ b/src/test/compile-fail/gated-unsafe-destructor.rs @@ -18,8 +18,6 @@ struct D<'a>(&'a u32); #[unsafe_destructor] //~^ ERROR `#[unsafe_destructor]` does nothing anymore -//~| HELP: add #![feature(unsafe_destructor)] to the crate attributes to enable -// (but of couse there is no point in doing so) impl<'a> Drop for D<'a> { fn drop(&mut self) { } } diff --git a/src/test/compile-fail/impl-unused-rps-in-assoc-type.rs b/src/test/compile-fail/impl-unused-rps-in-assoc-type.rs new file mode 100644 index 0000000000..23401db21d --- /dev/null +++ b/src/test/compile-fail/impl-unused-rps-in-assoc-type.rs @@ -0,0 +1,28 @@ +// 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. + +// Test that lifetime parameters must be constrained if they appear in +// an associated type def'n. Issue #22077. + +trait Fun { + type Output; + fn call<'x>(&'x self) -> Self::Output; +} + +struct Holder { x: String } + +impl<'a> Fun for Holder { //~ ERROR E0207 + type Output = &'a str; + fn call<'b>(&'b self) -> &'b str { + &self.x[..] + } +} + +fn main() { } diff --git a/src/test/compile-fail/implicit-method-bind.rs b/src/test/compile-fail/implicit-method-bind.rs index 6a9c304805..e116966670 100644 --- a/src/test/compile-fail/implicit-method-bind.rs +++ b/src/test/compile-fail/implicit-method-bind.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::num::SignedInt; - fn main() { - let _f = 10.abs; //~ ERROR attempted to take value of method + let _f = 10i32.abs; //~ ERROR attempted to take value of method } diff --git a/src/test/compile-fail/internal-unstable-noallow.rs b/src/test/compile-fail/internal-unstable-noallow.rs index 2b48d47e94..2e42e9d3b0 100644 --- a/src/test/compile-fail/internal-unstable-noallow.rs +++ b/src/test/compile-fail/internal-unstable-noallow.rs @@ -16,6 +16,8 @@ // aux-build:internal_unstable.rs // error-pattern:use of unstable library feature 'function' // error-pattern:use of unstable library feature 'struct_field' +// error-pattern:use of unstable library feature 'method' +// error-pattern:use of unstable library feature 'struct2_field' #[macro_use] extern crate internal_unstable; @@ -24,4 +26,8 @@ fn main() { call_unstable_noallow!(); construct_unstable_noallow!(0); + + |x: internal_unstable::Foo| { call_method_noallow!(x) }; + + |x: internal_unstable::Bar| { access_field_noallow!(x) }; } diff --git a/src/test/compile-fail/internal-unstable.rs b/src/test/compile-fail/internal-unstable.rs index accc898b8a..e01259f0de 100755 --- a/src/test/compile-fail/internal-unstable.rs +++ b/src/test/compile-fail/internal-unstable.rs @@ -36,6 +36,8 @@ fn main() { // ok, the instability is contained. call_unstable_allow!(); construct_unstable_allow!(0); + |x: internal_unstable::Foo| { call_method_allow!(x) }; + |x: internal_unstable::Bar| { access_field_allow!(x) }; // bad. pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable diff --git a/src/test/compile-fail/issue-13853-2.rs b/src/test/compile-fail/issue-13853-2.rs index dc697e4784..ea0d880f4a 100644 --- a/src/test/compile-fail/issue-13853-2.rs +++ b/src/test/compile-fail/issue-13853-2.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::PhantomFn; - -trait FromStructReader<'a> : PhantomFn<(Self,&'a ())> { } +trait FromStructReader<'a> { } trait ResponseHook { fn get<'a, T: FromStructReader<'a>>(&'a self); } diff --git a/src/test/compile-fail/issue-13853.rs b/src/test/compile-fail/issue-13853.rs index cd3f337c4a..251da2c6b3 100644 --- a/src/test/compile-fail/issue-13853.rs +++ b/src/test/compile-fail/issue-13853.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait Node : MarkerTrait { +trait Node { fn zomg(); } diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs index 0b846651ac..51deb99a4f 100644 --- a/src/test/compile-fail/issue-14853.rs +++ b/src/test/compile-fail/issue-14853.rs @@ -9,9 +9,8 @@ // except according to those terms. use std::fmt::Debug; -use std::marker::MarkerTrait; -trait Str : MarkerTrait {} +trait Str {} trait Something { fn yay(_: Option, thing: &[T]); diff --git a/src/test/compile-fail/issue-16048.rs b/src/test/compile-fail/issue-16048.rs index dbd3336962..46b7b933d8 100644 --- a/src/test/compile-fail/issue-16048.rs +++ b/src/test/compile-fail/issue-16048.rs @@ -29,7 +29,7 @@ impl<'a> Test<'a> for Foo<'a> { impl<'a> NoLifetime for Foo<'a> { fn get<'p, T : Test<'a>>(&self) -> T { //~^ ERROR lifetime parameters or bounds on method `get` do not match the trait declaration - return *self as T; //~ ERROR non-scalar cast: `Foo<'a>` as `T` + return *self as T; } } diff --git a/src/test/compile-fail/issue-16747.rs b/src/test/compile-fail/issue-16747.rs index 64334fe439..a3529c9ea9 100644 --- a/src/test/compile-fail/issue-16747.rs +++ b/src/test/compile-fail/issue-16747.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait ListItem<'a> : MarkerTrait { +trait ListItem<'a> { fn list_name() -> &'a str; } @@ -18,10 +16,10 @@ trait Collection { fn len(&self) -> usize; } struct List<'a, T: ListItem<'a>> { //~^ ERROR the parameter type `T` may not live long enough -//~^^ NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at +//~| HELP consider adding an explicit lifetime bound +//~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at slice: &'a [T] } -//~^ HELP consider adding an explicit lifetime bound impl<'a, T: ListItem<'a>> Collection for List<'a, T> { fn len(&self) -> usize { 0 diff --git a/src/test/compile-fail/issue-18107.rs b/src/test/compile-fail/issue-18107.rs index 60ab616d59..6300a1dc15 100644 --- a/src/test/compile-fail/issue-18107.rs +++ b/src/test/compile-fail/issue-18107.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -pub trait AbstractRenderer : MarkerTrait {} +pub trait AbstractRenderer {} fn _create_render(_: &()) -> AbstractRenderer diff --git a/src/test/compile-fail/issue-18389.rs b/src/test/compile-fail/issue-18389.rs index 271c31bd37..41be78dd7b 100644 --- a/src/test/compile-fail/issue-18389.rs +++ b/src/test/compile-fail/issue-18389.rs @@ -8,14 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(unboxed_closures)] - use std::any::Any; use std::any::TypeId; -use std::marker::MarkerTrait; -pub trait Pt : MarkerTrait {} -pub trait Rt : MarkerTrait {} +pub trait Pt {} +pub trait Rt {} trait Private { fn call(&self, p: P, r: R); diff --git a/src/test/compile-fail/issue-18611.rs b/src/test/compile-fail/issue-18611.rs index e81a576fa6..a662e9ca98 100644 --- a/src/test/compile-fail/issue-18611.rs +++ b/src/test/compile-fail/issue-18611.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - fn add_state(op: ::State) { //~^ ERROR the trait `HasState` is not implemented for the type `isize` } -trait HasState : MarkerTrait { +trait HasState { type State; } diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs index 951d78410b..d89b2c6ce8 100644 --- a/src/test/compile-fail/issue-18819.rs +++ b/src/test/compile-fail/issue-18819.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait { +trait Foo { type Item; } @@ -20,7 +18,7 @@ impl Foo for X { type Item = bool; } -fn print_x(_: &Foo, extra: &str) { +fn print_x(_: &Foo, extra: &str) { println!("{}", extra); } diff --git a/src/test/compile-fail/issue-19244-1.rs b/src/test/compile-fail/issue-19244-1.rs index 5c11787d46..0fa1a15477 100644 --- a/src/test/compile-fail/issue-19244-1.rs +++ b/src/test/compile-fail/issue-19244-1.rs @@ -12,7 +12,5 @@ const TUP: (usize,) = (42,); fn main() { let a: [isize; TUP.1]; - //~^ ERROR array length constant evaluation error: tuple index out of bounds - //~| ERROR attempted out-of-bounds tuple index - //~| ERROR attempted out-of-bounds tuple index + //~^ ERROR attempted out-of-bounds tuple index } diff --git a/src/test/compile-fail/issue-19244-2.rs b/src/test/compile-fail/issue-19244-2.rs index d896f76865..7d7d7d7c8c 100644 --- a/src/test/compile-fail/issue-19244-2.rs +++ b/src/test/compile-fail/issue-19244-2.rs @@ -13,7 +13,5 @@ const STRUCT: MyStruct = MyStruct { field: 42 }; fn main() { let a: [isize; STRUCT.nonexistent_field]; - //~^ ERROR array length constant evaluation error: nonexistent struct field - //~| ERROR attempted access of field `nonexistent_field` - //~| ERROR attempted access of field `nonexistent_field` + //~^ ERROR attempted access of field `nonexistent_field` } diff --git a/src/test/run-pass/issue-19121.rs b/src/test/compile-fail/issue-19482.rs similarity index 75% rename from src/test/run-pass/issue-19121.rs rename to src/test/compile-fail/issue-19482.rs index e02d001ee9..21a50f24d5 100644 --- a/src/test/run-pass/issue-19121.rs +++ b/src/test/compile-fail/issue-19482.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -9,7 +9,7 @@ // except according to those terms. // Test that a partially specified trait object with unspecified associated -// type does not ICE. +// type does not type-check. // pretty-expanded FIXME #23616 @@ -20,7 +20,6 @@ trait Foo { } fn bar(x: &Foo) {} -// FIXME(#19482) -- `Foo` should specify `A`, but this is not -// currently enforced except at object creation +//~^ ERROR the associated type `A` (from the trait `Foo`) must be specified pub fn main() {} diff --git a/src/test/compile-fail/issue-19660.rs b/src/test/compile-fail/issue-19660.rs index 4435ee0cb2..a4a8eac682 100644 --- a/src/test/compile-fail/issue-19660.rs +++ b/src/test/compile-fail/issue-19660.rs @@ -13,12 +13,8 @@ #![feature(lang_items, start, no_std)] #![no_std] -#[lang="phantom_fn"] -trait PhantomFn { } -impl PhantomFn for U { } - #[lang = "sized"] -trait Sized : PhantomFn {} +trait Sized { } #[start] fn main(_: isize, _: *const *const u8) -> isize { diff --git a/src/test/compile-fail/issue-2063.rs b/src/test/compile-fail/issue-2063.rs index aed395d17e..20bd8af7c3 100644 --- a/src/test/compile-fail/issue-2063.rs +++ b/src/test/compile-fail/issue-2063.rs @@ -12,11 +12,9 @@ // cause compiler to loop. Note that no instances // of such a type could ever be constructed. -use std::marker::MarkerTrait; - struct t(Box); //~ ERROR this type cannot be instantiated -trait to_str_2 : MarkerTrait { +trait to_str_2 { fn my_to_string() -> String; } @@ -28,7 +26,10 @@ impl to_str_2 for t { } fn new_t(x: t) { - x.my_to_string(); //~ ERROR does not implement + x.my_to_string(); + // (there used to be an error emitted right here as well. It was + // spurious, at best; if `t` did exist as a type, it clearly would + // have an impl of the `to_str_2` trait.) } fn main() { diff --git a/src/test/compile-fail/issue-20772.rs b/src/test/compile-fail/issue-20772.rs new file mode 100644 index 0000000000..44c92f946f --- /dev/null +++ b/src/test/compile-fail/issue-20772.rs @@ -0,0 +1,15 @@ +// 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. + +trait T : Iterator +//~^ ERROR unsupported cyclic reference between types/traits detected +{} + +fn main() {} diff --git a/src/test/compile-fail/issue-20831-debruijn.rs b/src/test/compile-fail/issue-20831-debruijn.rs index 5b623ac377..a38278eae2 100644 --- a/src/test/compile-fail/issue-20831-debruijn.rs +++ b/src/test/compile-fail/issue-20831-debruijn.rs @@ -14,10 +14,9 @@ // away. use std::cell::RefCell; -use std::marker::MarkerTrait; use std::ops::{Shl, Shr}; -pub trait Subscriber : MarkerTrait { +pub trait Subscriber { type Input; } diff --git a/src/test/compile-fail/issue-20939.rs b/src/test/compile-fail/issue-20939.rs new file mode 100644 index 0000000000..88197166ee --- /dev/null +++ b/src/test/compile-fail/issue-20939.rs @@ -0,0 +1,16 @@ +// 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. + +trait Foo {} + +impl<'a> Foo for Foo+'a {} +//~^ ERROR the object type `Foo + 'a` automatically implements the trait `Foo` + +fn main() {} diff --git a/src/test/compile-fail/issue-21950.rs b/src/test/compile-fail/issue-21950.rs new file mode 100644 index 0000000000..900ad5ce81 --- /dev/null +++ b/src/test/compile-fail/issue-21950.rs @@ -0,0 +1,20 @@ +// 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. + +// ignore-tidy-linelength + +use std::ops::Add; + +fn main() { + let x = &10 as + &Add; + //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self` + //~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified +} diff --git a/src/test/compile-fail/issue-22034.rs b/src/test/compile-fail/issue-22034.rs new file mode 100644 index 0000000000..004e33b76a --- /dev/null +++ b/src/test/compile-fail/issue-22034.rs @@ -0,0 +1,19 @@ +// 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. + +extern crate libc; + +fn main() { + let foo: *mut libc::c_void; + let cb: &mut Fn() = unsafe { + &mut *(foo as *mut Fn()) + //~^ ERROR use of possibly uninitialized variable: `foo` + }; +} diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs new file mode 100644 index 0000000000..f4f6aaa94f --- /dev/null +++ b/src/test/compile-fail/issue-22289.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + 0 as &std::any::Any; //~ ERROR non-scalar cast: `i32` as `&core::any::Any` +} diff --git a/src/test/compile-fail/issue-22370.rs b/src/test/compile-fail/issue-22370.rs new file mode 100644 index 0000000000..4c6652d812 --- /dev/null +++ b/src/test/compile-fail/issue-22370.rs @@ -0,0 +1,18 @@ +// 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. + +// ignore-tidy-linelength + +trait A {} + +fn f(a: &A) {} +//~^ ERROR the type parameter `T` must be explicitly specified in an object type because its default value `Self` references the type `Self` + +fn main() {} diff --git a/src/test/compile-fail/issue-22384.rs b/src/test/compile-fail/issue-22384.rs new file mode 100644 index 0000000000..368e248353 --- /dev/null +++ b/src/test/compile-fail/issue-22384.rs @@ -0,0 +1,18 @@ +// 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. + +trait Trait { + fn foo(); +} + +fn main() { + <::foobar as Trait>::foo(); + //~^ ERROR use of undeclared associated type `Copy::foobar` +} diff --git a/src/test/compile-fail/issue-22560.rs b/src/test/compile-fail/issue-22560.rs new file mode 100644 index 0000000000..a05bbe4960 --- /dev/null +++ b/src/test/compile-fail/issue-22560.rs @@ -0,0 +1,21 @@ +// 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. + +// ignore-tidy-linelength + +use std::ops::{Add, Sub}; + +type Test = Add + + //~^ ERROR the type parameter `RHS` must be explicitly specified in an object type because its default value `Self` references the type `Self` + //~^^ ERROR the value of the associated type `Output` (from the trait `core::ops::Add`) must be specified [E0191] + Sub; + //~^ ERROR only the builtin traits can be used as closure or object bounds + +fn main() { } diff --git a/src/test/compile-fail/issue-22886.rs b/src/test/compile-fail/issue-22886.rs new file mode 100644 index 0000000000..4aa2571cad --- /dev/null +++ b/src/test/compile-fail/issue-22886.rs @@ -0,0 +1,31 @@ +// 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. + +// Regression test for #22886. + +fn crash_please() { + let mut iter = Newtype(Some(Box::new(0))); + let saved = iter.next().unwrap(); + println!("{}", saved); + iter.0 = None; + println!("{}", saved); +} + +struct Newtype(Option>); + +impl<'a> Iterator for Newtype { //~ ERROR E0207 + type Item = &'a Box; + + fn next(&mut self) -> Option<&Box> { + self.0.as_ref() + } +} + +fn main() { } diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index ff5ac9de8d..b77230a8b3 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -12,9 +12,7 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -unsafe trait Trait: MarkerTrait { +unsafe trait Trait { //~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items type Output; } diff --git a/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs b/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs new file mode 100644 index 0000000000..993893438e --- /dev/null +++ b/src/test/compile-fail/issue-23338-locals-die-before-temps-of-body.rs @@ -0,0 +1,36 @@ +// 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. + +// This is just checking that we still reject code where temp values +// are borrowing values for longer than they will be around. +// +// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs + +use std::cell::RefCell; + +fn foo(x: RefCell) -> String { + let y = x; + y.borrow().clone() //~ ERROR `y` does not live long enough +} + +fn foo2(x: RefCell) -> String { + let ret = { + let y = x; + y.borrow().clone() //~ ERROR `y` does not live long enough + }; + ret +} + +fn main() { + let r = RefCell::new(format!("data")); + assert_eq!(foo(r), "data"); + let r = RefCell::new(format!("data")); + assert_eq!(foo2(r), "data"); +} diff --git a/src/test/compile-fail/issue-23729.rs b/src/test/compile-fail/issue-23729.rs new file mode 100644 index 0000000000..3d77d171ac --- /dev/null +++ b/src/test/compile-fail/issue-23729.rs @@ -0,0 +1,43 @@ +// 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. + +// Regression test for #23729 + +fn main() { + let fib = { + struct Recurrence { + mem: [u64; 2], + pos: usize, + } + + impl Iterator for Recurrence { + //~^ ERROR not all trait items implemented, missing: `Item` [E0046] + #[inline] + fn next(&mut self) -> Option { + if self.pos < 2 { + let next_val = self.mem[self.pos]; + self.pos += 1; + Some(next_val) + } else { + let next_val = (self.mem[0] + self.mem[1]); + self.mem[0] = self.mem[1]; + self.mem[1] = next_val; + Some(next_val) + } + } + } + + Recurrence { mem: [0, 1], pos: 0 } + }; + + for e in fib.take(10) { + println!("{}", e) + } +} diff --git a/src/test/compile-fail/issue-23827.rs b/src/test/compile-fail/issue-23827.rs new file mode 100644 index 0000000000..6c42c88bee --- /dev/null +++ b/src/test/compile-fail/issue-23827.rs @@ -0,0 +1,43 @@ +// 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. + +// Regression test for #23827 + +#![feature(core, unboxed_closures)] + +pub struct Prototype { + pub target: u32 +} + +trait Component { + fn apply(self, e: u32); +} + +impl Fn<(C,)> for Prototype { + extern "rust-call" fn call(&self, (comp,): (C,)) -> Prototype { + comp.apply(self.target); + *self + } +} + +impl FnMut<(C,)> for Prototype { + extern "rust-call" fn call_mut(&mut self, (comp,): (C,)) -> Prototype { + Fn::call(*&self, (comp,)) + } +} + +impl FnOnce<(C,)> for Prototype { + //~^ ERROR not all trait items implemented, missing: `Output` [E0046] + extern "rust-call" fn call_once(self, (comp,): (C,)) -> Prototype { + Fn::call(&self, (comp,)) + } +} + +fn main() {} diff --git a/src/test/compile-fail/issue-24036.rs b/src/test/compile-fail/issue-24036.rs new file mode 100644 index 0000000000..3c8a64eaf7 --- /dev/null +++ b/src/test/compile-fail/issue-24036.rs @@ -0,0 +1,30 @@ +// 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. + +fn closure_to_loc() { + let mut x = |c| c + 1; + x = |c| c + 1; + //~^ ERROR mismatched types + //~| NOTE no two closures, even if identical, have the same type + //~| HELP consider boxing your closure and/or using it as a trait object +} + +fn closure_from_match() { + let x = match 1usize { + 1 => |c| c + 1, + 2 => |c| c - 1, + _ => |c| c - 1 + }; + //~^^^^^ ERROR match arms have incompatible types + //~| NOTE no two closures, even if identical, have the same type + //~| HELP consider boxing your closure and/or using it as a trait object +} + +fn main() { } diff --git a/src/test/compile-fail/issue-24267-flow-exit.rs b/src/test/compile-fail/issue-24267-flow-exit.rs new file mode 100644 index 0000000000..4aca6bf38e --- /dev/null +++ b/src/test/compile-fail/issue-24267-flow-exit.rs @@ -0,0 +1,29 @@ +// 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. + +// Ensure that we reject code when a nonlocal exit (`break`, +// `continue`) causes us to pop over a needed assignment. + +pub fn main() { + foo1(); + foo2(); +} + +pub fn foo1() { + let x: i32; + loop { x = break; } + println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +} + +pub fn foo2() { + let x: i32; + for _ in 0..10 { x = continue; } + println!("{}", x); //~ ERROR use of possibly uninitialized variable: `x` +} diff --git a/src/test/compile-fail/issue-24356.rs b/src/test/compile-fail/issue-24356.rs new file mode 100644 index 0000000000..22f7183533 --- /dev/null +++ b/src/test/compile-fail/issue-24356.rs @@ -0,0 +1,40 @@ +// 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. + +// Regression test for #24356 + +// ignore-tidy-linelength + +fn main() { + { + use std::ops::Deref; + + struct Thing(i8); + + /* + // Correct impl + impl Deref for Thing { + type Target = i8; + fn deref(&self) -> &i8 { &self.0 } + } + */ + + // Causes ICE + impl Deref for Thing { + //~^ ERROR not all trait items implemented, missing: `Target` [E0046] + fn deref(&self) -> i8 { self.0 } + //~^ ERROR method `deref` has an incompatible type for trait: expected &-ptr, found i8 [E0053] + } + + let thing = Thing(72); + + *thing + }; +} diff --git a/src/test/compile-fail/issue-24365.rs b/src/test/compile-fail/issue-24365.rs new file mode 100644 index 0000000000..a4df42a8c7 --- /dev/null +++ b/src/test/compile-fail/issue-24365.rs @@ -0,0 +1,29 @@ +// 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. + +pub enum Attribute { + Code {attr_name_idx: u16}, +} + +pub enum Foo { + Bar +} + +fn test(a: Foo) { + println!("{}", a.b); //~ ERROR attempted access of field +} + +fn main() { + let x = Attribute::Code { + attr_name_idx: 42, + }; + let z = (&x).attr_name_idx; //~ ERROR attempted access of field + let y = x.attr_name_idx; //~ ERROR attempted access of field +} diff --git a/src/test/compile-fail/issue-3702-2.rs b/src/test/compile-fail/issue-3702-2.rs index 2b732899ea..026ee89c0b 100644 --- a/src/test/compile-fail/issue-3702-2.rs +++ b/src/test/compile-fail/issue-3702-2.rs @@ -8,7 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::num::ToPrimitive; +pub trait ToPrimitive { + fn to_int(&self) -> isize { 0 } +} + +impl ToPrimitive for i32 {} +impl ToPrimitive for isize {} trait Add { fn to_int(&self) -> isize; diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index 55a793f748..0089bff3e8 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -15,7 +15,7 @@ fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. id(Box::new(|| *v)) - //~^ ERROR `v` does not live long enough + //~^ ERROR E0373 //~| ERROR cannot move out of borrowed content } diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index d316b44794..9e324cdd61 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait I : MarkerTrait {} +trait I {} type K = I+'static; fn foo(_x: K) {} //~ ERROR: the trait `core::marker::Sized` is not implemented diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index b0db990619..9ff957b6e6 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait A : MarkerTrait {} +trait A {} struct Struct { r: A+'static @@ -22,6 +20,6 @@ fn new_struct(r: A+'static) Struct { r: r } } -trait Curve : MarkerTrait {} +trait Curve {} enum E {X(Curve+'static)} fn main() {} diff --git a/src/test/compile-fail/issue-7575.rs b/src/test/compile-fail/issue-7575.rs index 9c019f6ec4..6b320f400a 100644 --- a/src/test/compile-fail/issue-7575.rs +++ b/src/test/compile-fail/issue-7575.rs @@ -10,14 +10,12 @@ // Test the mechanism for warning about possible missing `self` declarations. -use std::marker::MarkerTrait; - trait CtxtFn { fn f8(self, usize) -> usize; fn f9(usize) -> usize; //~ NOTE candidate } -trait OtherTrait : MarkerTrait { +trait OtherTrait { fn f9(usize) -> usize; //~ NOTE candidate } @@ -26,7 +24,7 @@ trait OtherTrait : MarkerTrait { // declaration to match against, so we wind up prisizeing it as a // candidate. This seems not unreasonable -- perhaps the user meant to // implement it, after all. -trait UnusedTrait : MarkerTrait { +trait UnusedTrait { fn f9(usize) -> usize; //~ NOTE candidate } @@ -54,7 +52,7 @@ impl Myisize { } } -trait ManyImplTrait : MarkerTrait { +trait ManyImplTrait { fn is_str() -> bool { //~ NOTE candidate false } diff --git a/src/test/compile-fail/issue-8767.rs b/src/test/compile-fail/issue-8767.rs index 9abd8c9e3f..96c8ec4505 100644 --- a/src/test/compile-fail/issue-8767.rs +++ b/src/test/compile-fail/issue-8767.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - impl B { //~ ERROR use of undeclared type name `B` } diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 1925caf687..d43ddff6b9 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -10,12 +10,11 @@ // Test which of the builtin types are considered POD. -use std::marker::MarkerTrait; use std::rc::Rc; fn assert_copy() { } -trait Dummy : MarkerTrait { } +trait Dummy { } #[derive(Copy, Clone)] struct MyStruct { diff --git a/src/test/compile-fail/kindck-impl-type-params-2.rs b/src/test/compile-fail/kindck-impl-type-params-2.rs index fd0789421e..66297d70ef 100644 --- a/src/test/compile-fail/kindck-impl-type-params-2.rs +++ b/src/test/compile-fail/kindck-impl-type-params-2.rs @@ -10,9 +10,7 @@ #![feature(box_syntax)] -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait { +trait Foo { } impl Foo for T { diff --git a/src/test/compile-fail/kindck-impl-type-params.rs b/src/test/compile-fail/kindck-impl-type-params.rs index 71494fd5f3..d4ee93e9ca 100644 --- a/src/test/compile-fail/kindck-impl-type-params.rs +++ b/src/test/compile-fail/kindck-impl-type-params.rs @@ -41,7 +41,7 @@ fn g(val: T) { fn foo<'a>() { let t: S<&'a isize> = S(marker::PhantomData); let a = &t as &Gettable<&'a isize>; - //~^ ERROR cannot infer + //~^ ERROR does not fulfill } fn foo2<'a>() { diff --git a/src/test/compile-fail/kindck-send-object.rs b/src/test/compile-fail/kindck-send-object.rs index 0c68401bb2..570f7ad7fe 100644 --- a/src/test/compile-fail/kindck-send-object.rs +++ b/src/test/compile-fail/kindck-send-object.rs @@ -12,10 +12,8 @@ // in this file all test the "kind" violates detected during kindck. // See all `regions-bounded-by-send.rs` -use std::marker::MarkerTrait; - fn assert_send() { } -trait Dummy : MarkerTrait { } +trait Dummy { } trait Message : Send { } // careful with object types, who knows what they close over... diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs index f86eac8b16..48d5215b70 100644 --- a/src/test/compile-fail/kindck-send-object1.rs +++ b/src/test/compile-fail/kindck-send-object1.rs @@ -12,10 +12,8 @@ // is broken into two parts because some errors occur in distinct // phases in the compiler. See kindck-send-object2.rs as well! -use std::marker::MarkerTrait; - fn assert_send() { } -trait Dummy : MarkerTrait { } +trait Dummy { } // careful with object types, who knows what they close over... fn test51<'a>() { diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs index 08516e6731..d3d166e2a6 100644 --- a/src/test/compile-fail/kindck-send-object2.rs +++ b/src/test/compile-fail/kindck-send-object2.rs @@ -10,10 +10,8 @@ // Continue kindck-send-object1.rs. -use std::marker::MarkerTrait; - fn assert_send() { } -trait Dummy : MarkerTrait { } +trait Dummy { } fn test50() { assert_send::<&'static Dummy>(); //~ ERROR the trait `core::marker::Sync` is not implemented diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 391b49e106..16f195b4ea 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -12,7 +12,6 @@ // aux-build:inherited_stability.rs // aux-build:stability_cfg1.rs // aux-build:stability_cfg2.rs -// ignore-tidy-linelength #![deny(deprecated)] #![allow(dead_code)] diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index 798dc112b0..42515e0f00 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -52,12 +52,12 @@ fn qux() { } fn quy() { - let i = -23_us; //~ WARNING negation of unsigned int literal may be unintentional + let i = -23_usize; //~ WARNING negation of unsigned int literal may be unintentional //~^ WARNING unused variable } fn quz() { - let i = 23_us; + let i = 23_usize; let j = -i; //~ WARNING negation of unsigned int variable may be unintentional //~^ WARNING unused variable } diff --git a/src/test/compile-fail/lint-unsafe-code.rs b/src/test/compile-fail/lint-unsafe-code.rs index 8440cf3a88..10f245aaaf 100644 --- a/src/test/compile-fail/lint-unsafe-code.rs +++ b/src/test/compile-fail/lint-unsafe-code.rs @@ -12,18 +12,15 @@ #![allow(dead_code)] #![deny(unsafe_code)] -use std::marker::PhantomFn; - struct Bar; struct Bar2; struct Bar3; #[allow(unsafe_code)] mod allowed_unsafe { - use std::marker::PhantomFn; fn allowed() { unsafe {} } unsafe fn also_allowed() {} - unsafe trait AllowedUnsafe : PhantomFn {} + unsafe trait AllowedUnsafe { } unsafe impl AllowedUnsafe for super::Bar {} } @@ -34,7 +31,7 @@ macro_rules! unsafe_in_macro { } unsafe fn baz() {} //~ ERROR: declaration of an `unsafe` function -unsafe trait Foo : PhantomFn {} //~ ERROR: declaration of an `unsafe` trait +unsafe trait Foo {} //~ ERROR: declaration of an `unsafe` trait unsafe impl Foo for Bar {} //~ ERROR: implementation of an `unsafe` trait trait Baz { diff --git a/src/test/compile-fail/lint-uppercase-variables.rs b/src/test/compile-fail/lint-uppercase-variables.rs index 517be0eb8a..1615af4007 100644 --- a/src/test/compile-fail/lint-uppercase-variables.rs +++ b/src/test/compile-fail/lint-uppercase-variables.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![allow(dead_code)] #![deny(non_snake_case)] diff --git a/src/test/compile-fail/lint-visible-private-types.rs b/src/test/compile-fail/lint-visible-private-types.rs index 918b4ee209..c6dc3b70be 100644 --- a/src/test/compile-fail/lint-visible-private-types.rs +++ b/src/test/compile-fail/lint-visible-private-types.rs @@ -105,7 +105,7 @@ impl PrivTrait for (Private,) { fn bar(&self) -> Private { panic!() } } -pub trait ParamTrait : marker::MarkerTrait { +pub trait ParamTrait { fn foo() -> T; } diff --git a/src/test/compile-fail/loop-labeled-break-value.rs b/src/test/compile-fail/loop-labeled-break-value.rs index e1ae3ae464..f0792c145d 100644 --- a/src/test/compile-fail/loop-labeled-break-value.rs +++ b/src/test/compile-fail/loop-labeled-break-value.rs @@ -16,6 +16,6 @@ fn main() { let _: i32 = 'inner: loop { break 'inner }; //~ ERROR mismatched types } loop { - let _: i32 = 'inner: loop { loop { break 'inner } }; //~ ERROR mismatched types + let _: i32 = 'inner2: loop { loop { break 'inner2 } }; //~ ERROR mismatched types } } diff --git a/src/test/compile-fail/loops-reject-duplicate-labels-2.rs b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs new file mode 100644 index 0000000000..68627ecaa7 --- /dev/null +++ b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs @@ -0,0 +1,51 @@ +// 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. + +#![feature(rustc_attrs)] + +// ignore-tidy-linelength + +// Issue #21633: reject duplicate loop labels in function bodies. +// +// This is testing the generalization (to the whole function body) +// discussed here: +// http://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833 + +pub fn foo() { + { 'fl: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fl` declared here + { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope + + { 'lf: loop { break; } } //~ NOTE shadowed label `'lf` declared here + { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope + + { 'wl: while 2 > 1 { break; } } //~ NOTE shadowed label `'wl` declared here + { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope + + { 'lw: loop { break; } } //~ NOTE shadowed label `'lw` declared here + { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope + + { 'fw: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fw` declared here + { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope + + { 'wf: while 2 > 1 { break; } } //~ NOTE shadowed label `'wf` declared here + { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope + + { 'tl: while let Some(_) = None:: { break; } } //~ NOTE shadowed label `'tl` declared here + { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope + + { 'lt: loop { break; } } //~ NOTE shadowed label `'lt` declared here + { 'lt: while let Some(_) = None:: { break; } } + //~^ WARN label name `'lt` shadows a label name that is already in scope +} + +#[rustc_error] +pub fn main() { //~ ERROR compilation successful + foo(); +} diff --git a/src/test/compile-fail/loops-reject-duplicate-labels.rs b/src/test/compile-fail/loops-reject-duplicate-labels.rs new file mode 100644 index 0000000000..15446bf642 --- /dev/null +++ b/src/test/compile-fail/loops-reject-duplicate-labels.rs @@ -0,0 +1,60 @@ +// 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. + +#![feature(rustc_attrs)] + +// ignore-tidy-linelength + +// Issue #21633: reject duplicate loop labels in function bodies. +// This is testing the exact cases that are in the issue description. + +fn foo() { + 'fl: for _ in 0..10 { break; } //~ NOTE shadowed label `'fl` declared here + 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope + + 'lf: loop { break; } //~ NOTE shadowed label `'lf` declared here + 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope + + 'wl: while 2 > 1 { break; } //~ NOTE shadowed label `'wl` declared here + 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope + + 'lw: loop { break; } //~ NOTE shadowed label `'lw` declared here + 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope + + 'fw: for _ in 0..10 { break; } //~ NOTE shadowed label `'fw` declared here + 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope + + 'wf: while 2 > 1 { break; } //~ NOTE shadowed label `'wf` declared here + 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope + + 'tl: while let Some(_) = None:: { break; } //~ NOTE shadowed label `'tl` declared here + 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope + + 'lt: loop { break; } //~ NOTE shadowed label `'lt` declared here + 'lt: while let Some(_) = None:: { break; } + //~^ WARN label name `'lt` shadows a label name that is already in scope +} + +// Note however that it is okay for the same label to be reused in +// different methods of one impl, as illustrated here. + +struct S; +impl S { + fn m1(&self) { 'okay: loop { break 'okay; } } + fn m2(&self) { 'okay: loop { break 'okay; } } +} + +#[rustc_error] +pub fn main() { //~ ERROR compilation successful + let s = S; + s.m1(); + s.m2(); + foo(); +} diff --git a/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs new file mode 100644 index 0000000000..bbdd0774ed --- /dev/null +++ b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs @@ -0,0 +1,120 @@ +// 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. + +// Issue #21633: reject duplicate loop labels in function bodies. +// This is testing interaction between lifetime-params and labels. + +#![feature(rustc_attrs)] + +#![allow(dead_code, unused_variables)] + +fn foo() { + fn foo<'a>() { //~ NOTE shadowed lifetime `'a` declared here + 'a: loop { break 'a; } + //~^ WARN label name `'a` shadows a lifetime name that is already in scope + } + + struct Struct<'b, 'c> { _f: &'b i8, _g: &'c i8 } + enum Enum<'d, 'e> { A(&'d i8), B(&'e i8) } + + impl<'d, 'e> Struct<'d, 'e> { + fn meth_okay() { + 'a: loop { break 'a; } + 'b: loop { break 'b; } + 'c: loop { break 'c; } + } + } + + impl <'d, 'e> Enum<'d, 'e> { + fn meth_okay() { + 'a: loop { break 'a; } + 'b: loop { break 'b; } + 'c: loop { break 'c; } + } + } + + impl<'bad, 'c> Struct<'bad, 'c> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + + impl<'b, 'bad> Struct<'b, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad2(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + + impl<'b, 'c> Struct<'b, 'c> { + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + + fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { + //~^ NOTE shadowed lifetime `'bad` declared here + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + + impl <'bad, 'e> Enum<'bad, 'e> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + impl <'d, 'bad> Enum<'d, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad2(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + impl <'d, 'e> Enum<'d, 'e> { + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + + fn meth_bad4<'a,'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + + trait HasDefaultMethod1<'bad> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_okay() { + 'c: loop { break 'c; } + } + fn meth_bad(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + trait HasDefaultMethod2<'a,'bad> { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad(&self) { + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } + trait HasDefaultMethod3<'a,'b> { + fn meth_bad<'bad>(&self) { //~ NOTE shadowed lifetime `'bad` declared here + 'bad: loop { break 'bad; } + //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + } + } +} + +#[rustc_error] +pub fn main() { //~ ERROR compilation successful + foo(); +} diff --git a/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs new file mode 100644 index 0000000000..2344d251c9 --- /dev/null +++ b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs @@ -0,0 +1,41 @@ +// 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. + +#![feature(rustc_attrs)] + +#![allow(dead_code, unused_variables)] + +// Issue #21633: reject duplicate loop labels in function bodies. +// +// Test rejection of lifetimes in *expressions* that shadow loop labels. + +fn foo() { + // Reusing lifetime `'a` in function item is okay. + fn foo<'a>(x: &'a i8) -> i8 { *x } + + // So is reusing `'a` in struct item + struct S1<'a> { x: &'a i8 } impl<'a> S1<'a> { fn m(&self) {} } + // and a method item + struct S2; impl S2 { fn m<'a>(&self) {} } + + let z = 3_i8; + + 'a: loop { //~ NOTE shadowed label `'a` declared here + let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; + //~^ WARN lifetime name `'a` shadows a label name that is already in scope + assert_eq!((*b)(&z), z); + break 'a; + } +} + +#[rustc_error] +pub fn main() { //~ ERROR compilation successful + foo(); +} diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs new file mode 100644 index 0000000000..df906d7235 --- /dev/null +++ b/src/test/compile-fail/macro-backtrace-invalid-internals.rs @@ -0,0 +1,57 @@ +// 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. + +// Macros in statement vs expression position handle backtraces differently. + +macro_rules! fake_method_stmt { //~ NOTE in expansion of + () => { + 1.fake() //~ ERROR does not implement any method + } +} + +macro_rules! fake_field_stmt { //~ NOTE in expansion of + () => { + 1.fake //~ ERROR no field with that name + } +} + +macro_rules! fake_anon_field_stmt { //~ NOTE in expansion of + () => { + (1).0 //~ ERROR type was not a tuple + } +} + +macro_rules! fake_method_expr { //~ NOTE in expansion of + () => { + 1.fake() //~ ERROR does not implement any method + } +} + +macro_rules! fake_field_expr { + () => { + 1.fake + } +} + +macro_rules! fake_anon_field_expr { + () => { + (1).0 + } +} + +fn main() { + fake_method_stmt!(); //~ NOTE expansion site + fake_field_stmt!(); //~ NOTE expansion site + fake_anon_field_stmt!(); //~ NOTE expansion site + + let _ = fake_method_expr!(); //~ NOTE expansion site + let _ = fake_field_expr!(); //~ ERROR no field with that name + let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple +} diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/compile-fail/macro-backtrace-nested.rs new file mode 100644 index 0000000000..7c1dc1a468 --- /dev/null +++ b/src/test/compile-fail/macro-backtrace-nested.rs @@ -0,0 +1,29 @@ +// 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. + +// In expression position, but not statement position, when we expand a macro, +// we replace the span of the expanded expression with that of the call site. + +macro_rules! nested_expr { + () => (fake) +} + +macro_rules! call_nested_expr { + () => (nested_expr!()) +} + +macro_rules! call_nested_expr_sum { //~ NOTE in expansion of + () => { 1 + nested_expr!(); } //~ ERROR unresolved name +} + +fn main() { + 1 + call_nested_expr!(); //~ ERROR unresolved name + call_nested_expr_sum!(); //~ NOTE expansion site +} diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs new file mode 100644 index 0000000000..0c66bbfcf0 --- /dev/null +++ b/src/test/compile-fail/macro-backtrace-println.rs @@ -0,0 +1,29 @@ +// 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. + +// The `format_args!` syntax extension issues errors before code expansion +// has completed, but we still need a backtrace. + +// This test includes stripped-down versions of `print!` and `println!`, +// because we can't otherwise verify the lines of the backtrace. + +fn print(_args: std::fmt::Arguments) {} + +macro_rules! myprint { //~ NOTE in expansion of + ($($arg:tt)*) => (print(format_args!($($arg)*))); +} + +macro_rules! myprintln { //~ NOTE in expansion of + ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0` +} + +fn main() { + myprintln!("{}"); //~ NOTE expansion site +} diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index 53b29ccb0c..32770d9018 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -17,19 +17,20 @@ macro_rules! ignored_item { } macro_rules! ignored_expr { - () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + () => ( 1, //~ ERROR unexpected token: `,` + 2 ) //~ ERROR macro expansion ignores token `2` } macro_rules! ignored_pat { () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` } -ignored_item!(); +ignored_item!(); //~ NOTE caused by the macro expansion here fn main() { - ignored_expr!(); + ignored_expr!(); //~ NOTE caused by the macro expansion here match 1 { - ignored_pat!() => (), + ignored_pat!() => (), //~ NOTE caused by the macro expansion here _ => (), } } diff --git a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs index 59e910ec6a..b5401f7d12 100644 --- a/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs +++ b/src/test/compile-fail/non-constant-expr-for-fixed-len-vec.rs @@ -12,8 +12,8 @@ fn main() { fn bar(n: isize) { + // FIXME (#24414): This error message needs improvement. let _x: [isize; n]; //~^ ERROR no type for local variable - //~| ERROR array length constant evaluation error: non-constant path in constant expr } } diff --git a/src/test/compile-fail/object-does-not-impl-trait.rs b/src/test/compile-fail/object-does-not-impl-trait.rs index 607ab13d12..efbf3782f9 100644 --- a/src/test/compile-fail/object-does-not-impl-trait.rs +++ b/src/test/compile-fail/object-does-not-impl-trait.rs @@ -11,9 +11,7 @@ // Test that an object type `Box` is not considered to implement the // trait `Foo`. Issue #5087. -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait {} +trait Foo {} fn take_foo(f: F) {} fn take_object(f: Box) { take_foo(f); } //~^ ERROR the trait `Foo` is not implemented diff --git a/src/test/compile-fail/object-safety-no-static.rs b/src/test/compile-fail/object-safety-no-static.rs index aae829ec7b..6a010d4969 100644 --- a/src/test/compile-fail/object-safety-no-static.rs +++ b/src/test/compile-fail/object-safety-no-static.rs @@ -11,7 +11,7 @@ // Check that we correctly prevent users from making trait objects // from traits with static methods. -trait Foo : ::std::marker::MarkerTrait { +trait Foo { fn foo(); } diff --git a/src/test/compile-fail/object-safety-phantom-fn.rs b/src/test/compile-fail/object-safety-phantom-fn.rs index 1c95ee43d2..518c45ac9d 100644 --- a/src/test/compile-fail/object-safety-phantom-fn.rs +++ b/src/test/compile-fail/object-safety-phantom-fn.rs @@ -13,12 +13,10 @@ #![feature(rustc_attrs)] #![allow(dead_code)] -use std::marker::PhantomFn; - -trait Baz : PhantomFn { +trait Baz { } -trait Bar : PhantomFn<(Self, T)> { +trait Bar { } fn make_bar>(t: &T) -> &Bar { diff --git a/src/test/compile-fail/old-suffixes-are-really-forbidden.rs b/src/test/compile-fail/old-suffixes-are-really-forbidden.rs new file mode 100644 index 0000000000..b18741d393 --- /dev/null +++ b/src/test/compile-fail/old-suffixes-are-really-forbidden.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let a = 1_is; //~ ERROR illegal suffix + let b = 2_us; //~ ERROR illegal suffix +} diff --git a/src/test/compile-fail/on-unimplemented-bad-anno.rs b/src/test/compile-fail/on-unimplemented-bad-anno.rs index 7538b1c85e..8580749084 100644 --- a/src/test/compile-fail/on-unimplemented-bad-anno.rs +++ b/src/test/compile-fail/on-unimplemented-bad-anno.rs @@ -13,11 +13,8 @@ #![allow(unused)] -use std::marker; - #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"] trait Foo - : marker::PhantomFn<(Self,Bar,Baz,Quux)> {} #[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] @@ -28,19 +25,16 @@ trait MyFromIterator { #[rustc_on_unimplemented] //~ ERROR this attribute must have a value trait BadAnnotation1 - : marker::MarkerTrait {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] //~^ ERROR there is no type parameter C on trait BadAnnotation2 trait BadAnnotation2 - : marker::PhantomFn<(Self,A,B)> {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] //~^ only named substitution parameters are allowed trait BadAnnotation3 - : marker::PhantomFn<(Self,A,B)> {} pub fn main() { diff --git a/src/test/compile-fail/on-unimplemented.rs b/src/test/compile-fail/on-unimplemented.rs index 2447d08642..c4eb467c4f 100644 --- a/src/test/compile-fail/on-unimplemented.rs +++ b/src/test/compile-fail/on-unimplemented.rs @@ -11,11 +11,8 @@ #![feature(on_unimplemented)] -use std::marker; - #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"] trait Foo - : marker::PhantomFn<(Self,Bar,Baz,Quux)> {} fn foobar>() -> T { diff --git a/src/test/compile-fail/phantom-oibit.rs b/src/test/compile-fail/phantom-oibit.rs index c912d084da..071b4db40f 100644 --- a/src/test/compile-fail/phantom-oibit.rs +++ b/src/test/compile-fail/phantom-oibit.rs @@ -14,9 +14,9 @@ #![feature(optin_builtin_traits)] -use std::marker::{MarkerTrait, PhantomData}; +use std::marker::{PhantomData}; -unsafe trait Zen: MarkerTrait {} +unsafe trait Zen {} unsafe impl Zen for .. {} diff --git a/src/test/compile-fail/privacy-ns2.rs b/src/test/compile-fail/privacy-ns2.rs index 67bb566ea6..7fe0574ab7 100644 --- a/src/test/compile-fail/privacy-ns2.rs +++ b/src/test/compile-fail/privacy-ns2.rs @@ -17,9 +17,7 @@ // public type, private value pub mod foo1 { - use std::marker::MarkerTrait; - - pub trait Bar : MarkerTrait { + pub trait Bar { } pub struct Baz; @@ -41,7 +39,7 @@ fn test_list1() { // private type, public value pub mod foo2 { - trait Bar : ::std::marker::MarkerTrait { + trait Bar { } pub struct Baz; @@ -62,7 +60,7 @@ fn test_list2() { // neither public pub mod foo3 { - trait Bar : ::std::marker::MarkerTrait { + trait Bar { } pub struct Baz; diff --git a/src/test/compile-fail/privacy1.rs b/src/test/compile-fail/privacy1.rs index 67dccb4c93..f728fdfaf9 100644 --- a/src/test/compile-fail/privacy1.rs +++ b/src/test/compile-fail/privacy1.rs @@ -11,15 +11,11 @@ #![feature(lang_items, start, no_std)] #![no_std] // makes debugging this test *a lot* easier (during resolve) -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } - #[lang="sized"] -pub trait Sized : PhantomFn {} +pub trait Sized {} #[lang="copy"] -pub trait Copy : PhantomFn {} +pub trait Copy {} mod bar { // shouldn't bring in too much diff --git a/src/test/compile-fail/privacy4.rs b/src/test/compile-fail/privacy4.rs index adce93af07..bcb46663aa 100644 --- a/src/test/compile-fail/privacy4.rs +++ b/src/test/compile-fail/privacy4.rs @@ -11,12 +11,8 @@ #![feature(lang_items, start, no_std)] #![no_std] // makes debugging this test *a lot* easier (during resolve) -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } - -#[lang = "sized"] pub trait Sized : PhantomFn {} -#[lang="copy"] pub trait Copy : PhantomFn {} +#[lang = "sized"] pub trait Sized {} +#[lang="copy"] pub trait Copy {} // Test to make sure that private items imported through globs remain private // when they're used. diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 3ae61722bc..826e4283ef 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -19,6 +19,7 @@ pub fn main() { for i in false..true {} //~^ ERROR the trait //~^^ ERROR the trait + //~^^^ ERROR the trait // Unsized type. let arr: &[_] = &[1, 2, 3]; diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index 1bb2bb5a15..f95ee40589 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -11,7 +11,7 @@ // Test that attempts to implicitly coerce a value into an // object respect the lifetime bound on the object type. -trait Foo : ::std::marker::MarkerTrait {} +trait Foo {} impl<'a> Foo for &'a [u8] {} // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. diff --git a/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs index 6aa0cc003c..9a13541bd0 100644 --- a/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs +++ b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs @@ -15,11 +15,9 @@ #![allow(dead_code)] -use std::marker::PhantomFn; - /////////////////////////////////////////////////////////////////////////// -pub trait TheTrait: PhantomFn { +pub trait TheTrait { type TheAssocType; } diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs b/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs index 9736910d7b..0d3d2e296b 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs +++ b/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs @@ -14,11 +14,9 @@ #![allow(dead_code)] #![feature(rustc_attrs)] -use std::marker::PhantomFn; - /////////////////////////////////////////////////////////////////////////// -pub trait TheTrait<'b> : PhantomFn<&'b Self,Self> { +pub trait TheTrait<'b> { type TheAssocType; } diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs b/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs index da7546ce21..2ceaea98d2 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs +++ b/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs @@ -15,11 +15,9 @@ #![allow(dead_code)] -use std::marker::PhantomFn; - /////////////////////////////////////////////////////////////////////////// -pub trait TheTrait: PhantomFn { +pub trait TheTrait { type TheAssocType; } diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container.rs b/src/test/compile-fail/regions-assoc-type-outlives-container.rs index e1e72e6f56..e3e57ff171 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container.rs +++ b/src/test/compile-fail/regions-assoc-type-outlives-container.rs @@ -15,11 +15,9 @@ #![allow(dead_code)] #![feature(rustc_attrs)] -use std::marker::PhantomFn; - /////////////////////////////////////////////////////////////////////////// -pub trait TheTrait: PhantomFn { +pub trait TheTrait { type TheAssocType; } diff --git a/src/test/compile-fail/regions-close-associated-type-into-object.rs b/src/test/compile-fail/regions-close-associated-type-into-object.rs index f80b0ffa5a..fdc97ecaf2 100644 --- a/src/test/compile-fail/regions-close-associated-type-into-object.rs +++ b/src/test/compile-fail/regions-close-associated-type-into-object.rs @@ -12,9 +12,7 @@ // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. -use std::marker::MarkerTrait; - -trait X : MarkerTrait {} +trait X {} trait Iter { type Item: X; diff --git a/src/test/compile-fail/regions-close-object-into-object-1.rs b/src/test/compile-fail/regions-close-object-into-object-1.rs index 4c831a2b65..5472e09ba4 100644 --- a/src/test/compile-fail/regions-close-object-into-object-1.rs +++ b/src/test/compile-fail/regions-close-object-into-object-1.rs @@ -11,12 +11,10 @@ #![feature(box_syntax)] #![allow(warnings)] -use std::marker::PhantomFn; - -trait A : PhantomFn<(Self,T)> { } +trait A { } struct B<'a, T>(&'a (A+'a)); -trait X : ::std::marker::MarkerTrait {} +trait X { } impl<'a, T> X for B<'a, T> {} diff --git a/src/test/compile-fail/regions-close-object-into-object-2.rs b/src/test/compile-fail/regions-close-object-into-object-2.rs index 6de49020a6..1ef000852d 100644 --- a/src/test/compile-fail/regions-close-object-into-object-2.rs +++ b/src/test/compile-fail/regions-close-object-into-object-2.rs @@ -10,12 +10,10 @@ #![feature(box_syntax)] -use std::marker::PhantomFn; - -trait A : PhantomFn<(Self,T)> { } +trait A { } struct B<'a, T>(&'a (A+'a)); -trait X : PhantomFn {} +trait X { } impl<'a, T> X for B<'a, T> {} fn g<'a, T: 'static>(v: Box+'a>) -> Box { diff --git a/src/test/compile-fail/regions-close-object-into-object-3.rs b/src/test/compile-fail/regions-close-object-into-object-3.rs index b723efff3c..b7dc759b27 100644 --- a/src/test/compile-fail/regions-close-object-into-object-3.rs +++ b/src/test/compile-fail/regions-close-object-into-object-3.rs @@ -11,15 +11,13 @@ #![feature(box_syntax)] #![allow(warnings)] -use std::marker::PhantomFn; - -trait A : PhantomFn<(Self,T)> {} +trait A { } struct B<'a, T>(&'a (A+'a)); -trait X : PhantomFn {} +trait X { } impl<'a, T> X for B<'a, T> {} -fn h<'a, T, U>(v: Box+'static>) -> Box { +fn h<'a, T, U:'static>(v: Box+'static>) -> Box { box B(&*v) as Box //~ ERROR `*v` does not live long enough } diff --git a/src/test/compile-fail/regions-close-object-into-object-4.rs b/src/test/compile-fail/regions-close-object-into-object-4.rs index 9b311588bb..247578d253 100644 --- a/src/test/compile-fail/regions-close-object-into-object-4.rs +++ b/src/test/compile-fail/regions-close-object-into-object-4.rs @@ -10,12 +10,10 @@ #![feature(box_syntax)] -use std::marker::PhantomFn; - -trait A : PhantomFn<(Self,T)> {} +trait A { } struct B<'a, T>(&'a (A+'a)); -trait X : PhantomFn {} +trait X { } impl<'a, T> X for B<'a, T> {} fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs index 2341d2397c..25b8137d29 100644 --- a/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs +++ b/src/test/compile-fail/regions-close-over-borrowed-ref-in-obj.rs @@ -10,9 +10,7 @@ #![feature(box_syntax)] -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait { } +trait Foo { } impl<'a> Foo for &'a isize { } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index bdebadb283..948dc8cd21 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -13,7 +13,7 @@ fn ignore(_f: F) where F: for<'z> FnOnce(&'z isize) -> &'z isize {} fn nested() { let y = 3; ignore( - |z| { //~ ERROR `y` does not live long enough + |z| { //~ ERROR E0373 if false { &y } else { z } }); } diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index 1b749faf1b..bb80c763a8 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,11 +11,7 @@ #![feature(lang_items, no_std)] #![no_std] -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } - -#[lang="sized"] pub trait Sized : PhantomFn {} +#[lang="sized"] pub trait Sized { } // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/retslot-cast.rs b/src/test/compile-fail/retslot-cast.rs index 4ef07ecb43..c5e26a2674 100644 --- a/src/test/compile-fail/retslot-cast.rs +++ b/src/test/compile-fail/retslot-cast.rs @@ -11,7 +11,8 @@ #![feature(rustc_attrs)] #![allow(warnings)] -pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { +pub fn fail(x: Option<&(Iterator+Send)>) + -> Option<&Iterator> { // This call used to trigger an LLVM assertion because the return // slot had type "Option<&Iterator>"* instead of // "Option<&(Iterator+Send)>"* -- but this now yields a @@ -23,7 +24,8 @@ pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> { inner(x) //~ ERROR mismatched types } -pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> { +pub fn inner(x: Option<&(Iterator+Send)>) + -> Option<&(Iterator+Send)> { x } diff --git a/src/test/compile-fail/self-impl.rs b/src/test/compile-fail/self-impl.rs new file mode 100644 index 0000000000..d058c6a5a3 --- /dev/null +++ b/src/test/compile-fail/self-impl.rs @@ -0,0 +1,40 @@ +// 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. + +// Test that unsupported uses of `Self` in impls don't crash + +struct Bar; + +trait Foo { + type Baz; +} + +trait SuperFoo { + type SuperBaz; +} + +impl Foo for Bar { + type Baz = bool; +} + +impl SuperFoo for Bar { + type SuperBaz = bool; +} + +impl Bar { + fn f() { + let _: ::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + let _: Self::Baz = true; +//~^ERROR: ambiguous associated type; specify the type using the syntax `::Baz` + } +} + +fn main() {} diff --git a/src/test/compile-fail/shadowed-lifetime.rs b/src/test/compile-fail/shadowed-lifetime.rs index 725f83d495..8cbab5f830 100644 --- a/src/test/compile-fail/shadowed-lifetime.rs +++ b/src/test/compile-fail/shadowed-lifetime.rs @@ -15,16 +15,14 @@ struct Foo<'a>(&'a isize); impl<'a> Foo<'a> { //~^ NOTE shadowed lifetime `'a` declared here fn shadow_in_method<'a>(&'a self) -> &'a isize { - //~^ WARNING lifetime name `'a` shadows another lifetime name that is already in scope - //~| NOTE deprecated + //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope self.0 } fn shadow_in_type<'b>(&'b self) -> &'b isize { //~^ NOTE shadowed lifetime `'b` declared here let x: for<'b> fn(&'b isize) = panic!(); - //~^ WARNING lifetime name `'b` shadows another lifetime name that is already in scope - //~| NOTE deprecated + //~^ ERROR lifetime name `'b` shadows a lifetime name that is already in scope self.0 } @@ -35,9 +33,4 @@ impl<'a> Foo<'a> { } fn main() { - // intentional error that occurs after `resolve_lifetime` runs, - // just to ensure that this test fails to compile; when shadowed - // lifetimes become either an error or a proper lint, this will - // not be needed. - let x: isize = 3_usize; //~ ERROR mismatched types } diff --git a/src/test/compile-fail/stability-attribute-non-staged.rs b/src/test/compile-fail/stability-attribute-non-staged.rs new file mode 100644 index 0000000000..b0efdfd181 --- /dev/null +++ b/src/test/compile-fail/stability-attribute-non-staged.rs @@ -0,0 +1,14 @@ +// 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. + +#[unstable] //~ ERROR: stability attributes may not be used +#[stable] //~ ERROR: stability attributes may not be used +#[deprecated] //~ ERROR: stability attributes may not be used +fn main() { } diff --git a/src/test/compile-fail/struct-base-wrong-type-2.rs b/src/test/compile-fail/struct-base-wrong-type-2.rs new file mode 100644 index 0000000000..83e73b6bc3 --- /dev/null +++ b/src/test/compile-fail/struct-base-wrong-type-2.rs @@ -0,0 +1,31 @@ +// Copyright 2013 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. + +// Check that `base` in `Fru { field: expr, ..base }` must have right type. +// +// See also struct-base-wrong-type.rs, which tests same condition +// within a const expression. + +struct Foo { a: isize, b: isize } +struct Bar { x: isize } + +fn main() { + let b = Bar { x: 5 }; + let f = Foo { a: 2, ..b }; //~ ERROR mismatched types + //~| expected `Foo` + //~| found `Bar` + //~| expected struct `Foo` + //~| found struct `Bar` + let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types + //~| expected `Foo` + //~| found `_` + //~| expected struct `Foo` + //~| found integral variable +} diff --git a/src/test/compile-fail/struct-base-wrong-type.rs b/src/test/compile-fail/struct-base-wrong-type.rs index a2ad2336d4..c98131560d 100644 --- a/src/test/compile-fail/struct-base-wrong-type.rs +++ b/src/test/compile-fail/struct-base-wrong-type.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Check that `base` in `Fru { field: expr, ..base }` must have right type. +// +// See also struct-base-wrong-type-2.rs, which tests same condition +// within a function body. + struct Foo { a: isize, b: isize } struct Bar { x: isize } @@ -25,14 +30,10 @@ static foo_i: Foo = Foo { a: 2, ..4 }; //~ ERROR mismatched types fn main() { let b = Bar { x: 5 }; - let f = Foo { a: 2, ..b }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `Bar` - //~| expected struct `Foo` - //~| found struct `Bar` - let f__isize = Foo { a: 2, ..4 }; //~ ERROR mismatched types - //~| expected `Foo` - //~| found `_` - //~| expected struct `Foo` - //~| found integral variable + // errors below are no longer caught since error above causes + // compilation to abort before we bother checking function bodies. + // See also struct-base-wrong-type-2.rs, which checks that we + // would catch these errors eventually. + let f = Foo { a: 2, ..b }; + let f__isize = Foo { a: 2, ..4 }; } diff --git a/src/test/compile-fail/trait-as-struct-constructor.rs b/src/test/compile-fail/trait-as-struct-constructor.rs index 1fd711ca4f..b864e6ca95 100644 --- a/src/test/compile-fail/trait-as-struct-constructor.rs +++ b/src/test/compile-fail/trait-as-struct-constructor.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait TraitNotAStruct : ::std::marker::MarkerTrait { } +trait TraitNotAStruct {} fn main() { TraitNotAStruct{ value: 0 }; diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs b/src/test/compile-fail/trait-bounds-impl-comparison-1.rs index 34e06cc936..a2369f8ffb 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-1.rs +++ b/src/test/compile-fail/trait-bounds-impl-comparison-1.rs @@ -13,8 +13,7 @@ use std::marker; -trait A : marker::PhantomFn { -} +trait A { } trait B: A {} diff --git a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs b/src/test/compile-fail/trait-bounds-impl-comparison-2.rs index 217540415a..beabdcea2b 100644 --- a/src/test/compile-fail/trait-bounds-impl-comparison-2.rs +++ b/src/test/compile-fail/trait-bounds-impl-comparison-2.rs @@ -15,7 +15,6 @@ trait Iterator { } trait IteratorUtil - : ::std::marker::PhantomFn<(),A> { fn zip>(self, other: U) -> ZipIterator; } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs index ce0a7d3bb3..c18c5b386e 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait Trait : MarkerTrait {} +trait Trait {} struct Foo { x: T, diff --git a/src/test/compile-fail/trait-bounds-sugar.rs b/src/test/compile-fail/trait-bounds-sugar.rs index e4058a0943..0a36fcbed6 100644 --- a/src/test/compile-fail/trait-bounds-sugar.rs +++ b/src/test/compile-fail/trait-bounds-sugar.rs @@ -10,9 +10,7 @@ // Tests for "default" bounds inferred for traits with no bounds list. -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait {} +trait Foo {} fn a(_x: Box) { } diff --git a/src/test/compile-fail/trait-impl-1.rs b/src/test/compile-fail/trait-impl-1.rs index 2f4793b4d8..dadcbd5bce 100644 --- a/src/test/compile-fail/trait-impl-1.rs +++ b/src/test/compile-fail/trait-impl-1.rs @@ -12,9 +12,7 @@ // trait impl is only applied to a trait object, not concrete types which implement // the trait. -use std::marker::MarkerTrait; - -trait T : MarkerTrait {} +trait T {} impl<'a> T+'a { fn foo(&self) {} diff --git a/src/test/compile-fail/type-params-in-different-spaces-1.rs b/src/test/compile-fail/type-params-in-different-spaces-1.rs index 88d8788d63..155b835bbc 100644 --- a/src/test/compile-fail/type-params-in-different-spaces-1.rs +++ b/src/test/compile-fail/type-params-in-different-spaces-1.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::num::Int; +use std::ops::Add; -trait BrokenAdd: Int { +trait BrokenAdd: Copy + Add { fn broken_add(&self, rhs: T) -> Self { *self + rhs //~ ERROR mismatched types //~| expected `Self` @@ -20,7 +20,7 @@ trait BrokenAdd: Int { } } -impl BrokenAdd for T {} +impl> BrokenAdd for T {} pub fn main() { let foo: u8 = 0; diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs index 0f3453da43..a27f7f7ebb 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types-2.rs @@ -10,9 +10,7 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait {} +trait MyTrait {} impl MyTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs index 524f467e01..24819bb4f0 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-constituent-types.rs @@ -10,9 +10,7 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait {} +trait MyTrait {} impl MyTrait for .. {} impl !MyTrait for *mut T {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-negation.rs b/src/test/compile-fail/typeck-default-trait-impl-negation.rs index a1ca0e3e0f..4b91d0b7a7 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-negation.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-negation.rs @@ -10,13 +10,11 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait {} +trait MyTrait {} impl MyTrait for .. {} -unsafe trait MyUnsafeTrait: MarkerTrait {} +unsafe trait MyUnsafeTrait {} unsafe impl MyUnsafeTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs index a345bd1b65..09b97dfb30 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-outside-crate.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(optin_builtin_traits)] impl Copy for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs index 4006eb2e83..c67fc92313 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-precedence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-precedence.rs @@ -15,15 +15,13 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait Defaulted : MarkerTrait { } +trait Defaulted { } impl Defaulted for .. { } impl<'a,T:Signed> Defaulted for &'a T { } impl<'a,T:Signed> Defaulted for &'a mut T { } fn is_defaulted() { } -trait Signed : MarkerTrait { } +trait Signed { } impl Signed for i32 { } fn main() { diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs index 4a6a77ac7b..aa918119fb 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs @@ -13,8 +13,6 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - trait MyTrait : 'static {} impl MyTrait for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs index 7f24058e47..c9bfdff6c0 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs @@ -13,9 +13,7 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; - -trait NotImplemented: MarkerTrait { } +trait NotImplemented { } trait MyTrait : NotImplemented {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs index c970aaaf5d..4f572e8763 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs @@ -15,11 +15,9 @@ #![feature(optin_builtin_traits)] -use std::marker::MarkerTrait; +trait NotImplemented { } -trait NotImplemented: MarkerTrait { } - -trait MyTrait: MarkerTrait +trait MyTrait where Option : NotImplemented {} diff --git a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs index 6d315c1b7a..dc5576aee6 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-equiv.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-equiv.rs @@ -16,14 +16,12 @@ #![feature(unboxed_closures)] #![allow(dead_code)] -use std::marker::PhantomFn; - trait Foo { type Output; fn dummy(&self, t: T, u: Self::Output); } -trait Eq : PhantomFn<(Self,X)> { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs index bd3530e6e3..a6f59b7882 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-lifetime-elision.rs @@ -23,7 +23,7 @@ trait Foo { fn dummy(&self, t: T); } -trait Eq : marker::PhantomFn<(Self, X)> { } +trait Eq { } impl Eq for X { } fn eq>() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs index 55156e28cd..5a821ef123 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-not-used-on-fn.rs @@ -11,7 +11,7 @@ // Test that the `Fn` traits require `()` form without a feature gate. -fn bar1(x: &Fn<()>) { +fn bar1(x: &Fn<(), Output=()>) { //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs index c9837da58e..bb7e02d0d8 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs @@ -12,7 +12,7 @@ trait One { fn foo(&self) -> A; } -fn foo(_: &One()) //~ ERROR no associated type `Output` defined in `One<()>` +fn foo(_: &One()) //~ ERROR associated type `Output` not found for `One<()>` {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs index 9f0682df3f..20fdd52b82 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs @@ -14,7 +14,7 @@ trait Three { fn dummy(&self) -> (A,B,C); } fn foo(_: &Three()) //~^ ERROR wrong number of type arguments -//~| ERROR no associated type `Output` +//~| ERROR associated type `Output` not found {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs index 40635cf3dd..027fa6b0fe 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-number-number-type-parameters.rs @@ -14,7 +14,7 @@ trait Zero { fn dummy(&self); } fn foo(_: Zero()) //~^ ERROR wrong number of type arguments - //~| ERROR no associated type `Output` defined in `Zero` + //~| ERROR associated type `Output` not found for `Zero` {} fn main() { } diff --git a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs index e6e18d996b..04bbfc445e 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-wrong-trait.rs @@ -14,6 +14,6 @@ trait Trait {} fn f isize>(x: F) {} //~^ ERROR wrong number of type arguments: expected 0, found 1 -//~| ERROR no associated type `Output` +//~| ERROR associated type `Output` not found fn main() {} diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index f31a6ffdc0..3f18f359d3 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -10,9 +10,7 @@ // Test `?Sized` local variables. -use std::marker; - -trait T : marker::MarkerTrait { } +trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. diff --git a/src/test/compile-fail/unsized7.rs b/src/test/compile-fail/unsized7.rs index 6ea3d0720e..0245a1b5cf 100644 --- a/src/test/compile-fail/unsized7.rs +++ b/src/test/compile-fail/unsized7.rs @@ -10,9 +10,7 @@ // Test sized-ness checking in substitution in impls. -use std::marker::MarkerTrait; - -trait T : MarkerTrait {} +trait T {} // I would like these to fail eventually. // impl - bounded diff --git a/src/test/compile-fail/unsupported-cast.rs b/src/test/compile-fail/unsupported-cast.rs index ca17c898ec..b4246f2ed8 100644 --- a/src/test/compile-fail/unsupported-cast.rs +++ b/src/test/compile-fail/unsupported-cast.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test FIXME: #13993 -// error-pattern:unsupported cast +// error-pattern:illegal cast + +#![feature(libc)] extern crate libc; diff --git a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs index 26d22b072e..addc572175 100644 --- a/src/test/compile-fail/use-after-move-implicity-coerced-object.rs +++ b/src/test/compile-fail/use-after-move-implicity-coerced-object.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-tidy-linelength - #![feature(box_syntax)] use std::fmt; diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs new file mode 100644 index 0000000000..94055450bc --- /dev/null +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -0,0 +1,43 @@ +// Copyright 2013 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. + +extern { + fn foo(f: isize, x: u8, ...); +} + +extern "C" fn bar(f: isize, x: u8) {} + +fn main() { + unsafe { + foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied + foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied + + let x: unsafe extern "C" fn(f: isize, x: u8) = foo; + //~^ ERROR: mismatched types + //~| expected `unsafe extern "C" fn(isize, u8)` + //~| found `unsafe extern "C" fn(isize, u8, ...)` + //~| expected non-variadic fn + //~| found variadic function + + let y: extern "C" fn(f: isize, x: u8, ...) = bar; + //~^ ERROR: mismatched types + //~| expected `extern "C" fn(isize, u8, ...)` + //~| found `extern "C" fn(isize, u8) {bar}` + //~| expected variadic fn + //~| found non-variadic function + + foo(1, 2, 3f32); //~ ERROR: can't pass an f32 to variadic function, cast to c_double + foo(1, 2, true); //~ ERROR: can't pass bool to variadic function, cast to c_int + foo(1, 2, 1i8); //~ ERROR: can't pass i8 to variadic function, cast to c_int + foo(1, 2, 1u8); //~ ERROR: can't pass u8 to variadic function, cast to c_uint + foo(1, 2, 1i16); //~ ERROR: can't pass i16 to variadic function, cast to c_int + foo(1, 2, 1u16); //~ ERROR: can't pass u16 to variadic function, cast to c_uint + } +} diff --git a/src/test/compile-fail/variadic-ffi.rs b/src/test/compile-fail/variadic-ffi.rs index 2a62ac2ac3..1294217849 100644 --- a/src/test/compile-fail/variadic-ffi.rs +++ b/src/test/compile-fail/variadic-ffi.rs @@ -19,29 +19,20 @@ extern { extern "C" fn bar(f: isize, x: u8) {} fn main() { + // errors below are no longer checked because error above aborts + // compilation; see variadic-ffi-3.rs for corresponding test. unsafe { - foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied + foo(); + foo(1); let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - //~^ ERROR: mismatched types - //~| expected `unsafe extern "C" fn(isize, u8)` - //~| found `unsafe extern "C" fn(isize, u8, ...)` - //~| expected non-variadic fn - //~| found variadic function - let y: extern "C" fn(f: isize, x: u8, ...) = bar; - //~^ ERROR: mismatched types - //~| expected `extern "C" fn(isize, u8, ...)` - //~| found `extern "C" fn(isize, u8) {bar}` - //~| expected variadic fn - //~| found non-variadic function - foo(1, 2, 3f32); //~ ERROR: can't pass an f32 to variadic function, cast to c_double - foo(1, 2, true); //~ ERROR: can't pass bool to variadic function, cast to c_int - foo(1, 2, 1i8); //~ ERROR: can't pass i8 to variadic function, cast to c_int - foo(1, 2, 1u8); //~ ERROR: can't pass u8 to variadic function, cast to c_uint - foo(1, 2, 1i16); //~ ERROR: can't pass i16 to variadic function, cast to c_int - foo(1, 2, 1u16); //~ ERROR: can't pass u16 to variadic function, cast to c_uint + foo(1, 2, 3f32); + foo(1, 2, true); + foo(1, 2, 1i8); + foo(1, 2, 1u8); + foo(1, 2, 1i16); + foo(1, 2, 1u16); } } diff --git a/src/test/compile-fail/variance-contravariant-arg-object.rs b/src/test/compile-fail/variance-contravariant-arg-object.rs index 3330e1d0d5..1795ac9535 100644 --- a/src/test/compile-fail/variance-contravariant-arg-object.rs +++ b/src/test/compile-fail/variance-contravariant-arg-object.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `T` is only used in contravariant position, it +// is treated as invariant. + trait Get : 'static { fn get(&self, t: T); } @@ -25,7 +28,8 @@ fn get_max_from_min<'min, 'max, G>(v: Box>) -> Box> where 'max : 'min { - v + // Previously OK: + v //~ ERROR mismatched types } fn main() { } diff --git a/src/test/compile-fail/variance-contravariant-arg-trait-match.rs b/src/test/compile-fail/variance-contravariant-arg-trait-match.rs index caaad4014a..9b6e3c9de3 100644 --- a/src/test/compile-fail/variance-contravariant-arg-trait-match.rs +++ b/src/test/compile-fail/variance-contravariant-arg-trait-match.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `T` is only used in contravariant position, it +// is treated as invariant. + trait Get { fn get(&self, t: T); } @@ -23,7 +26,9 @@ fn get_min_from_max<'min, 'max, G>() fn get_max_from_min<'min, 'max, G>() where 'max : 'min, G : Get<&'min i32> { - impls_get::() + // Previously OK, but now an error because traits are invariant: + + impls_get::() //~ ERROR mismatched types } fn impls_get() where G : Get { } diff --git a/src/test/compile-fail/variance-contravariant-self-trait-match.rs b/src/test/compile-fail/variance-contravariant-self-trait-match.rs index 013511ed51..6d9d1e61fe 100644 --- a/src/test/compile-fail/variance-contravariant-self-trait-match.rs +++ b/src/test/compile-fail/variance-contravariant-self-trait-match.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `Self` is only used in contravariant position, it +// is treated as invariant. + trait Get { fn get(&self); } @@ -23,7 +26,10 @@ fn get_min_from_max<'min, 'max, G>() fn get_max_from_min<'min, 'max, G>() where 'max : 'min, G : 'max, &'min G : Get { - impls_get::<&'max G>(); + // Previously OK, but now error because traits are invariant with + // respect to all inputs. + + impls_get::<&'max G>(); //~ ERROR mismatched types } fn impls_get() where G : Get { } diff --git a/src/test/compile-fail/variance-covariant-arg-object.rs b/src/test/compile-fail/variance-covariant-arg-object.rs index 828c987c08..ad059a467f 100644 --- a/src/test/compile-fail/variance-covariant-arg-object.rs +++ b/src/test/compile-fail/variance-covariant-arg-object.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `T` is only used in covariant position, it +// is treated as invariant. + trait Get : 'static { fn get(&self) -> T; } @@ -18,7 +21,8 @@ fn get_min_from_max<'min, 'max>(v: Box>) -> Box> where 'max : 'min { - v + // Previously OK, now an error as traits are invariant. + v //~ ERROR mismatched types } fn get_max_from_min<'min, 'max, G>(v: Box>) diff --git a/src/test/compile-fail/variance-covariant-arg-trait-match.rs b/src/test/compile-fail/variance-covariant-arg-trait-match.rs index 17761b9c0b..c42a845b3b 100644 --- a/src/test/compile-fail/variance-covariant-arg-trait-match.rs +++ b/src/test/compile-fail/variance-covariant-arg-trait-match.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `T` is only used in covariant position, it +// is treated as invariant. + trait Get { fn get(&self) -> T; } @@ -17,7 +20,8 @@ trait Get { fn get_min_from_max<'min, 'max, G>() where 'max : 'min, G : Get<&'max i32> { - impls_get::() + // Previously OK, now an error as traits are invariant. + impls_get::() //~ ERROR mismatched types } fn get_max_from_min<'min, 'max, G>() diff --git a/src/test/compile-fail/variance-covariant-self-trait-match.rs b/src/test/compile-fail/variance-covariant-self-trait-match.rs index 4e94a3eeb4..25148dfc02 100644 --- a/src/test/compile-fail/variance-covariant-self-trait-match.rs +++ b/src/test/compile-fail/variance-covariant-self-trait-match.rs @@ -10,6 +10,9 @@ #![allow(dead_code)] +// Test that even when `Self` is only used in covariant position, it +// is treated as invariant. + trait Get { fn get() -> Self; } @@ -17,7 +20,8 @@ trait Get { fn get_min_from_max<'min, 'max, G>() where 'max : 'min, G : 'max, &'max G : Get { - impls_get::<&'min G>(); + // Previously OK, now an error as traits are invariant. + impls_get::<&'min G>(); //~ ERROR mismatched types } fn get_max_from_min<'min, 'max, G>() diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index 96ae201f6a..dfa5dc1444 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,11 +13,11 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[[];[-];[]] +trait Foo: 'static { //~ ERROR types=[[];[o];[]] } #[rustc_variance] -trait Bar { //~ ERROR types=[[+];[-];[]] +trait Bar { //~ ERROR types=[[o];[o];[]] fn do_it(&self) where T: 'static; } diff --git a/src/test/compile-fail/variance-regions-unused-direct.rs b/src/test/compile-fail/variance-regions-unused-direct.rs index 396e776520..037fff72c8 100644 --- a/src/test/compile-fail/variance-regions-unused-direct.rs +++ b/src/test/compile-fail/variance-regions-unused-direct.rs @@ -18,7 +18,7 @@ struct Struct<'a, 'd> { //~ ERROR parameter `'d` is never used field: &'a [i32] } -trait Trait<'a, 'd> { //~ ERROR parameter `'d` is never used +trait Trait<'a, 'd> { // OK on traits fn method(&'a self); } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 88b50058b6..222d8338aa 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -16,12 +16,12 @@ // influence variance. #[rustc_variance] -trait Getter { //~ ERROR types=[[+];[-];[]] +trait Getter { //~ ERROR types=[[o];[o];[]] fn get(&self) -> T; } #[rustc_variance] -trait Setter { //~ ERROR types=[[-];[-];[]] +trait Setter { //~ ERROR types=[[o];[o];[]] fn get(&self, T); } @@ -37,16 +37,16 @@ enum TestEnum> {//~ ERROR types=[[*, +];[];[]] } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[[-, +];[-];[]] +trait TestTrait> { //~ ERROR types=[[o, o];[o];[]] fn getter(&self, u: U) -> T; } #[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR types=[[+];[-];[]] +trait TestTrait2 : Getter { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -trait TestTrait3 { //~ ERROR types=[[-];[-];[]] +trait TestTrait3 { //~ ERROR types=[[o];[o];[]] fn getter>(&self); } diff --git a/src/test/compile-fail/variance-trait-matching.rs b/src/test/compile-fail/variance-trait-matching.rs index ec020f1881..49dc1e68c2 100644 --- a/src/test/compile-fail/variance-trait-matching.rs +++ b/src/test/compile-fail/variance-trait-matching.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,22 +8,43 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Issue #5781. Tests that subtyping is handled properly in trait matching. +// pretty-expanded FIXME #23616 -trait Make<'a> { - fn make(x: &'a mut isize) -> Self; +#![allow(dead_code)] + +// Get is covariant in T +trait Get { + fn get(&self) -> T; +} + +struct Cloner { + t: T } -impl<'a> Make<'a> for &'a mut isize { - fn make(x: &'a mut isize) -> &'a mut isize { - x +impl Get for Cloner { + fn get(&self) -> T { + self.t.clone() } } -fn f() -> &'static mut isize { - let mut x = 1; - let y: &'static mut isize = Make::make(&mut x); //~ ERROR `x` does not live long enough - y +fn get<'a, G>(get: &G) -> i32 + where G : Get<&'a i32> +{ + // This fails to type-check because, without variance, we can't + // use `G : Get<&'a i32>` as evidence that `G : Get<&'b i32>`, + // even if `'a : 'b`. + pick(get, &22) //~ ERROR cannot infer } -fn main() {} +fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32 + where G : Get<&'b i32> +{ + let v = *get.get(); + if v % 2 != 0 { v } else { *if_odd } +} + +fn main() { + let x = Cloner { t: &23 }; + let y = get(&x); + assert_eq!(y, 23); +} diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index d53e4cd761..a02f20656e 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -37,12 +37,12 @@ struct TestIndirect2 { //~ ERROR types=[[o, o];[];[]] } #[rustc_variance] -trait Getter { //~ ERROR types=[[+];[-];[]] +trait Getter { //~ ERROR types=[[o];[o];[]] fn get(&self) -> A; } #[rustc_variance] -trait Setter { //~ ERROR types=[[-];[o];[]] +trait Setter { //~ ERROR types=[[o];[o];[]] fn set(&mut self, a: A); } @@ -53,7 +53,7 @@ trait GetterSetter { //~ ERROR types=[[o];[o];[]] } #[rustc_variance] -trait GetterInTypeBound { //~ ERROR types=[[-];[-];[]] +trait GetterInTypeBound { //~ ERROR types=[[o];[o];[]] // Here, the use of `A` in the method bound *does* affect // variance. Think of it as if the method requested a dictionary // for `T:Getter`. Since this dictionary is an input, it is @@ -63,12 +63,12 @@ trait GetterInTypeBound { //~ ERROR types=[[-];[-];[]] } #[rustc_variance] -trait SetterInTypeBound { //~ ERROR types=[[+];[-];[]] +trait SetterInTypeBound { //~ ERROR types=[[o];[o];[]] fn do_it>(&self); } #[rustc_variance] -struct TestObject { //~ ERROR types=[[-, +];[];[]] +struct TestObject { //~ ERROR types=[[o, o];[];[]] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-unused-region-param.rs b/src/test/compile-fail/variance-unused-region-param.rs index 5f50422637..407282e5ce 100644 --- a/src/test/compile-fail/variance-unused-region-param.rs +++ b/src/test/compile-fail/variance-unused-region-param.rs @@ -12,6 +12,6 @@ struct SomeStruct<'a> { x: u32 } //~ ERROR parameter `'a` is never used enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used -trait SomeTrait<'a> { fn foo(&self); } //~ ERROR parameter `'a` is never used +trait SomeTrait<'a> { fn foo(&self); } // OK on traits. fn main() {} diff --git a/src/test/compile-fail/variance-unused-type-param.rs b/src/test/compile-fail/variance-unused-type-param.rs index 2e867ec3c9..862d842d62 100644 --- a/src/test/compile-fail/variance-unused-type-param.rs +++ b/src/test/compile-fail/variance-unused-type-param.rs @@ -21,10 +21,6 @@ enum SomeEnum { Nothing } //~^ ERROR parameter `A` is never used //~| HELP PhantomData -trait SomeTrait { fn foo(&self); } -//~^ ERROR parameter `A` is never used -//~| HELP PhantomFn - // Here T might *appear* used, but in fact it isn't. enum ListCell { //~^ ERROR parameter `T` is never used diff --git a/src/test/compile-fail/wrong-mul-method-signature.rs b/src/test/compile-fail/wrong-mul-method-signature.rs index 21c249c0e1..069fd2dec9 100644 --- a/src/test/compile-fail/wrong-mul-method-signature.rs +++ b/src/test/compile-fail/wrong-mul-method-signature.rs @@ -71,16 +71,9 @@ pub fn main() { let x: Vec1 = Vec1 { x: 1.0 } * 2.0; // this is OK let x: Vec2 = Vec2 { x: 1.0, y: 2.0 } * 2.0; // trait had reversed order - //~^ ERROR mismatched types - //~| expected `Vec2` - //~| found `_` - //~| expected struct `Vec2` - //~| found floating-point variable - //~| ERROR mismatched types - //~| expected `Vec2` - //~| found `f64` - //~| expected struct `Vec2` - //~| found f64 + // (we no longer signal a compile error here, since the + // error in the trait signature will cause compilation to + // abort before we bother looking at function bodies.) let x: i32 = Vec3 { x: 1.0, y: 2.0, z: 3.0 } * 2.0; } diff --git a/src/test/debuginfo/associated-types.rs b/src/test/debuginfo/associated-types.rs index 63132d9132..d203806c08 100644 --- a/src/test/debuginfo/associated-types.rs +++ b/src/test/debuginfo/associated-types.rs @@ -30,7 +30,7 @@ // gdb-command:continue // gdb-command:print arg -// gdb-check:$5 = {4, 5} +// gdb-check:$5 = {__0 = 4, __1 = 5} // gdb-command:continue // gdb-command:print a diff --git a/src/test/debuginfo/borrowed-enum.rs b/src/test/debuginfo/borrowed-enum.rs index 87e9e7fe2d..732383b5e4 100644 --- a/src/test/debuginfo/borrowed-enum.rs +++ b/src/test/debuginfo/borrowed-enum.rs @@ -18,13 +18,13 @@ // gdb-command:run // gdb-command:print *the_a_ref -// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, 0, 2088533116, 2088533116}} +// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} // gdb-command:print *the_b_ref -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, 0, 286331153, 286331153}} +// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} // gdb-command:print *univariant_ref -// gdb-check:$3 = {{4820353753753434}} +// gdb-check:$3 = {{__0 = 4820353753753434}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index 768bcc9fc3..add9bdcead 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -17,13 +17,13 @@ // gdb-command:run // gdb-command:print *stack_val_ref -// gdb-check:$1 = {-14, -19} +// gdb-check:$1 = {__0 = -14, __1 = -19} // gdb-command:print *ref_to_unnamed -// gdb-check:$2 = {-15, -20} +// gdb-check:$2 = {__0 = -15, __1 = -20} // gdb-command:print *unique_val_ref -// gdb-check:$3 = {-17, -22} +// gdb-check:$3 = {__0 = -17, __1 = -22} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index 0689a6bc45..e5f4306b24 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -19,7 +19,7 @@ // gdb-command:print *a // gdb-check:$1 = 1 // gdb-command:print *b -// gdb-check:$2 = {2, 3.5} +// gdb-check:$2 = {__0 = 2, __1 = 3.5} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/by-value-non-immediate-argument.rs b/src/test/debuginfo/by-value-non-immediate-argument.rs index bc1116b064..1e89d0e31b 100644 --- a/src/test/debuginfo/by-value-non-immediate-argument.rs +++ b/src/test/debuginfo/by-value-non-immediate-argument.rs @@ -30,15 +30,15 @@ // gdb-command:continue // gdb-command:print a -// gdb-check:$5 = {7, 8, 9.5, 10.5} +// gdb-check:$5 = {__0 = 7, __1 = 8, __2 = 9.5, __3 = 10.5} // gdb-command:continue // gdb-command:print a -// gdb-check:$6 = {11.5, 12.5, 13, 14} +// gdb-check:$6 = {__0 = 11.5, __1 = 12.5, __2 = 13, __3 = 14} // gdb-command:continue // gdb-command:print x -// gdb-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, 0, 2088533116, 2088533116}} +// gdb-check:$7 = {{RUST$ENUM$DISR = Case1, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}} // gdb-command:continue diff --git a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs index 5bd872f9fa..39da48f9e7 100644 --- a/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs +++ b/src/test/debuginfo/by-value-self-argument-in-trait-impl.rs @@ -25,7 +25,7 @@ // gdb-command:continue // gdb-command:print self -// gdb-check:$3 = {4444.5, 5555, 6666, 7777.5} +// gdb-check:$3 = {__0 = 4444.5, __1 = 5555, __2 = 6666, __3 = 7777.5} // gdb-command:continue diff --git a/src/test/debuginfo/c-style-enum-in-composite.rs b/src/test/debuginfo/c-style-enum-in-composite.rs index c7a4daa42f..562b0d588f 100644 --- a/src/test/debuginfo/c-style-enum-in-composite.rs +++ b/src/test/debuginfo/c-style-enum-in-composite.rs @@ -18,13 +18,13 @@ // gdb-command:run // gdb-command:print tuple_interior_padding -// gdb-check:$1 = {0, OneHundred} +// gdb-check:$1 = {__0 = 0, __1 = OneHundred} // gdb-command:print tuple_padding_at_end -// gdb-check:$2 = {{1, OneThousand}, 2} +// gdb-check:$2 = {__0 = {__0 = 1, __1 = OneThousand}, __1 = 2} // gdb-command:print tuple_different_enums -// gdb-check:$3 = {OneThousand, MountainView, OneMillion, Vienna} +// gdb-check:$3 = {__0 = OneThousand, __1 = MountainView, __2 = OneMillion, __3 = Vienna} // gdb-command:print padded_struct // gdb-check:$4 = {a = 3, b = OneMillion, c = 4, d = Toronto, e = 5} @@ -36,7 +36,7 @@ // gdb-check:$6 = {a = OneMillion, b = MountainView, c = OneThousand, d = Toronto} // gdb-command:print struct_with_drop -// gdb-check:$7 = {{a = OneHundred, b = Vienna}, 9} +// gdb-check:$7 = {__0 = {a = OneHundred, b = Vienna}, __1 = 9} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/cross-crate-spans.rs b/src/test/debuginfo/cross-crate-spans.rs index 3aef9438a3..85b4e9babe 100644 --- a/src/test/debuginfo/cross-crate-spans.rs +++ b/src/test/debuginfo/cross-crate-spans.rs @@ -25,7 +25,7 @@ extern crate cross_crate_spans; // gdb-command:run // gdb-command:print result -// gdb-check:$1 = {17, 17} +// gdb-check:$1 = {__0 = 17, __1 = 17} // gdb-command:print a_variable // gdb-check:$2 = 123456789 // gdb-command:print another_variable @@ -33,7 +33,7 @@ extern crate cross_crate_spans; // gdb-command:continue // gdb-command:print result -// gdb-check:$4 = {1212, 1212} +// gdb-check:$4 = {__0 = 1212, __1 = 1212} // gdb-command:print a_variable // gdb-check:$5 = 123456789 // gdb-command:print another_variable diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index d7ec567325..5d330e16a1 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -33,7 +33,7 @@ // gdb-command:print a // gdb-check:$6 = 5 // gdb-command:print b -// gdb-check:$7 = {6, 7} +// gdb-check:$7 = {__0 = 6, __1 = 7} // gdb-command:continue // gdb-command:print h @@ -95,11 +95,11 @@ // gdb-command:continue // gdb-command:print aa -// gdb-check:$30 = {34, 35} +// gdb-check:$30 = {__0 = 34, __1 = 35} // gdb-command:continue // gdb-command:print bb -// gdb-check:$31 = {36, 37} +// gdb-check:$31 = {__0 = 36, __1 = 37} // gdb-command:continue // gdb-command:print cc @@ -107,17 +107,17 @@ // gdb-command:continue // gdb-command:print dd -// gdb-check:$33 = {40, 41, 42} +// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} // gdb-command:continue // gdb-command:print *ee -// gdb-check:$34 = {43, 44, 45} +// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} // gdb-command:continue // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {47, 48} +// gdb-check:$36 = {__0 = 47, __1 = 48} // gdb-command:continue // gdb-command:print *hh diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs index 9f0492f35a..ad04f97fb0 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -77,7 +77,7 @@ // gdb-command:continue // gdb-command:print simple_tuple_ident -// gdb-check:$24 = {34903493, 232323} +// gdb-check:$24 = {__0 = 34903493, __1 = 232323} // gdb-command:continue // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index 4b1c57e0af..632f17bd20 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -31,7 +31,7 @@ // gdb-command:print f // gdb-check:$6 = 5 // gdb-command:print g -// gdb-check:$7 = {6, 7} +// gdb-check:$7 = {__0 = 6, __1 = 7} // gdb-command:print h // gdb-check:$8 = 8 @@ -85,25 +85,25 @@ // gdb-check:$29 = 33 // gdb-command:print aa -// gdb-check:$30 = {34, 35} +// gdb-check:$30 = {__0 = 34, __1 = 35} // gdb-command:print bb -// gdb-check:$31 = {36, 37} +// gdb-check:$31 = {__0 = 36, __1 = 37} // gdb-command:print cc // gdb-check:$32 = 38 // gdb-command:print dd -// gdb-check:$33 = {40, 41, 42} +// gdb-check:$33 = {__0 = 40, __1 = 41, __2 = 42} // gdb-command:print *ee -// gdb-check:$34 = {43, 44, 45} +// gdb-check:$34 = {__0 = 43, __1 = 44, __2 = 45} // gdb-command:print *ff // gdb-check:$35 = 46 // gdb-command:print gg -// gdb-check:$36 = {47, 48} +// gdb-check:$36 = {__0 = 47, __1 = 48} // gdb-command:print *hh // gdb-check:$37 = 50 diff --git a/src/test/debuginfo/function-arg-initialization.rs b/src/test/debuginfo/function-arg-initialization.rs index d611e4a65a..a1ca59caa3 100644 --- a/src/test/debuginfo/function-arg-initialization.rs +++ b/src/test/debuginfo/function-arg-initialization.rs @@ -10,15 +10,15 @@ // min-lldb-version: 310 -// This test case checks if function arguments already have the correct value when breaking at the -// first line of the function, that is if the function prologue has already been executed at the -// first line. Note that because of the __morestack part of the prologue GDB incorrectly breaks at -// before the arguments have been properly loaded when setting the breakpoint via the function name. +// This test case checks if function arguments already have the correct value +// when breaking at the first line of the function, that is if the function +// prologue has already been executed at the first line. Note that because of +// the __morestack part of the prologue GDB incorrectly breaks at before the +// arguments have been properly loaded when setting the breakpoint via the +// function name. // compile-flags:-g -#![feature(old_io)] - // === GDB TESTS =================================================================================== // gdb-command:run @@ -227,7 +227,7 @@ #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { - ::std::old_io::print("") // #break + println!("") // #break } struct BigStruct { @@ -242,21 +242,21 @@ struct BigStruct { } fn non_immediate_args(a: BigStruct, b: BigStruct) { - ::std::old_io::print("") // #break + println!("") // #break } fn binding(a: i64, b: u64, c: f64) { let x = 0; // #break - ::std::old_io::print("") + println!("") } fn assignment(mut a: u64, b: u64, c: f64) { a = b; // #break - ::std::old_io::print("") + println!("") } fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") // #break + println!("Hi!") // #break } fn identifier(x: u64, y: u64, z: f64) -> u64 { diff --git a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs index 0608e49b28..7e959a1e92 100644 --- a/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs +++ b/src/test/debuginfo/function-prologue-stepping-no-stack-check.rs @@ -11,17 +11,17 @@ // ignore-android: FIXME(#10381) // min-lldb-version: 310 -// This test case checks if function arguments already have the correct value when breaking at the -// beginning of a function. Functions with the #[no_stack_check] attribute have the same prologue as -// regular C functions compiled with GCC or Clang and therefore are better handled by GDB. As a -// consequence, and as opposed to regular Rust functions, we can set the breakpoints via the -// function name (and don't have to fall back on using line numbers). For LLDB this shouldn't make -// a difference because it can handle both cases. +// This test case checks if function arguments already have the correct value +// when breaking at the beginning of a function. Functions with the +// #[no_stack_check] attribute have the same prologue as regular C functions +// compiled with GCC or Clang and therefore are better handled by GDB. As a +// consequence, and as opposed to regular Rust functions, we can set the +// breakpoints via the function name (and don't have to fall back on using line +// numbers). For LLDB this shouldn't make a difference because it can handle +// both cases. // compile-flags:-g -#![feature(old_io)] - // === GDB TESTS =================================================================================== // gdb-command:rbreak immediate_args @@ -251,7 +251,7 @@ #[no_stack_check] fn immediate_args(a: isize, b: bool, c: f64) { - ::std::old_io::print(""); + println!(""); } struct BigStruct { @@ -267,24 +267,24 @@ struct BigStruct { #[no_stack_check] fn non_immediate_args(a: BigStruct, b: BigStruct) { - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn binding(a: i64, b: u64, c: f64) { let x = 0; - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn assignment(mut a: u64, b: u64, c: f64) { a = b; - ::std::old_io::print(""); + println!(""); } #[no_stack_check] fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") + println!("Hi!") } #[no_stack_check] diff --git a/src/test/debuginfo/function-prologue-stepping-regular.rs b/src/test/debuginfo/function-prologue-stepping-regular.rs index e1a77b34e7..b34f1af01f 100644 --- a/src/test/debuginfo/function-prologue-stepping-regular.rs +++ b/src/test/debuginfo/function-prologue-stepping-regular.rs @@ -126,7 +126,6 @@ // lldb-command:continue #![allow(unused_variables)] -#![feature(old_io)] #![omit_gdb_pretty_printer_section] fn immediate_args(a: isize, b: bool, c: f64) { @@ -157,7 +156,7 @@ fn assignment(mut a: u64, b: u64, c: f64) { } fn function_call(x: u64, y: u64, z: f64) { - std::old_io::stdio::print("Hi!") + println!("Hi!") } fn identifier(x: u64, y: u64, z: f64) -> u64 { diff --git a/src/test/debuginfo/gdb-pretty-std.rs b/src/test/debuginfo/gdb-pretty-std.rs index dbf80a9bcc..1da9a06b0e 100644 --- a/src/test/debuginfo/gdb-pretty-std.rs +++ b/src/test/debuginfo/gdb-pretty-std.rs @@ -10,7 +10,6 @@ // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new -// ignore-tidy-linelength // ignore-lldb // ignore-android: FIXME(#10381) // compile-flags:-g diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs index aa6051d792..0d8b42a9f7 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs @@ -12,6 +12,7 @@ // older versions of GDB too. A more extensive test can be found in // gdb-pretty-struct-and-enums.rs +// ignore-bitrig // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new // ignore-tidy-linelength diff --git a/src/test/debuginfo/generic-function.rs b/src/test/debuginfo/generic-function.rs index 1748083b2b..890133c58c 100644 --- a/src/test/debuginfo/generic-function.rs +++ b/src/test/debuginfo/generic-function.rs @@ -21,7 +21,7 @@ // gdb-command:print *t1 // gdb-check:$2 = 2.5 // gdb-command:print ret -// gdb-check:$3 = {{1, 2.5}, {2.5, 1}} +// gdb-check:$3 = {__0 = {__0 = 1, __1 = 2.5}, __1 = {__0 = 2.5, __1 = 1}} // gdb-command:continue // gdb-command:print *t0 @@ -29,7 +29,7 @@ // gdb-command:print *t1 // gdb-check:$5 = 4 // gdb-command:print ret -// gdb-check:$6 = {{3.5, 4}, {4, 3.5}} +// gdb-check:$6 = {__0 = {__0 = 3.5, __1 = 4}, __1 = {__0 = 4, __1 = 3.5}} // gdb-command:continue // gdb-command:print *t0 @@ -37,7 +37,7 @@ // gdb-command:print *t1 // gdb-check:$8 = {a = 6, b = 7.5} // gdb-command:print ret -// gdb-check:$9 = {{5, {a = 6, b = 7.5}}, {{a = 6, b = 7.5}, 5}} +// gdb-check:$9 = {__0 = {__0 = 5, __1 = {a = 6, b = 7.5}}, __1 = {__0 = {a = 6, b = 7.5}, __1 = 5}} // gdb-command:continue diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index fc9ef8e3a9..14df15242d 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -18,7 +18,7 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {8888, -8888}} +// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +27,7 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {8888, -8888}} +// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 diff --git a/src/test/debuginfo/generic-tuple-style-enum.rs b/src/test/debuginfo/generic-tuple-style-enum.rs index b0f0852c69..83340c83dc 100644 --- a/src/test/debuginfo/generic-tuple-style-enum.rs +++ b/src/test/debuginfo/generic-tuple-style-enum.rs @@ -19,16 +19,16 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, 0, 31868, 31868, 31868, 31868}, {RUST$ENUM$DISR = Case1, 0, 2088533116, 2088533116}, {RUST$ENUM$DISR = Case1, 0, 8970181431921507452}} +// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, 0, 4369, 4369, 4369, 4369}, {RUST$ENUM$DISR = Case2, 0, 286331153, 286331153}, {RUST$ENUM$DISR = Case2, 0, 1229782938247303441}} +// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, 0, 22873, 22873, 22873, 22873}, {RUST$ENUM$DISR = Case3, 0, 1499027801, 1499027801}, {RUST$ENUM$DISR = Case3, 0, 6438275382588823897}} +// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} // gdb-command:print univariant -// gdb-check:$4 = {{-1}} +// gdb-check:$4 = {{__0 = -1}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/issue13213.rs b/src/test/debuginfo/issue13213.rs index 38b149ef24..13dc0c6d12 100644 --- a/src/test/debuginfo/issue13213.rs +++ b/src/test/debuginfo/issue13213.rs @@ -23,5 +23,5 @@ extern crate issue13213aux; // be available because they have been optimized out from the exporting crate. fn main() { let b: issue13213aux::S = issue13213aux::A; - ::std::old_io::println("Nothing to do here..."); + println!("Nothing to do here..."); } diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 6468a36f8c..77a11db8ba 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -19,7 +19,7 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, 117901063}} +// gdb-check:$1 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -28,7 +28,7 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, 117901063}} +// gdb-check:$4 = {{RUST$ENUM$DISR = Variant2, [...]}, {RUST$ENUM$DISR = Variant2, __0 = 117901063}} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 975668baa1..f76f8c8cad 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -18,7 +18,7 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {x = {8888, -8888}} +// gdb-check:$1 = {x = {__0 = 8888, __1 = -8888}} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +27,7 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {x = {8888, -8888}} +// gdb-check:$4 = {x = {__0 = 8888, __1 = -8888}} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index 97d4496cce..4ea0fd4447 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -18,7 +18,7 @@ // STACK BY REF // gdb-command:print *self -// gdb-check:$1 = {100, -100.5} +// gdb-check:$1 = {__0 = 100, __1 = -100.5} // gdb-command:print arg1 // gdb-check:$2 = -1 // gdb-command:print arg2 @@ -27,7 +27,7 @@ // STACK BY VAL // gdb-command:print self -// gdb-check:$4 = {100, -100.5} +// gdb-check:$4 = {__0 = 100, __1 = -100.5} // gdb-command:print arg1 // gdb-check:$5 = -3 // gdb-command:print arg2 @@ -36,7 +36,7 @@ // OWNED BY REF // gdb-command:print *self -// gdb-check:$7 = {200, -200.5} +// gdb-check:$7 = {__0 = 200, __1 = -200.5} // gdb-command:print arg1 // gdb-check:$8 = -5 // gdb-command:print arg2 @@ -45,7 +45,7 @@ // OWNED BY VAL // gdb-command:print self -// gdb-check:$10 = {200, -200.5} +// gdb-check:$10 = {__0 = 200, __1 = -200.5} // gdb-command:print arg1 // gdb-check:$11 = -7 // gdb-command:print arg2 @@ -54,7 +54,7 @@ // OWNED MOVED // gdb-command:print *self -// gdb-check:$13 = {200, -200.5} +// gdb-check:$13 = {__0 = 200, __1 = -200.5} // gdb-command:print arg1 // gdb-check:$14 = -9 // gdb-command:print arg2 diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs index 03336c3586..65a83088d8 100644 --- a/src/test/debuginfo/option-like-enum.rs +++ b/src/test/debuginfo/option-like-enum.rs @@ -18,13 +18,13 @@ // gdb-command:run // gdb-command:print some -// gdb-check:$1 = {RUST$ENCODED$ENUM$0$None = {0x12345678}} +// gdb-check:$1 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x12345678}} // gdb-command:print none -// gdb-check:$2 = {RUST$ENCODED$ENUM$0$None = {0x0}} +// gdb-check:$2 = {RUST$ENCODED$ENUM$0$None = {__0 = 0x0}} // gdb-command:print full -// gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {454545, 0x87654321, 9988}} +// gdb-check:$3 = {RUST$ENCODED$ENUM$1$Empty = {__0 = 454545, __1 = 0x87654321, __2 = 9988}} // gdb-command:print empty_gdb->discr // gdb-check:$4 = (isize *) 0x0 @@ -36,10 +36,10 @@ // gdb-check:$6 = (isize *) 0x0 // gdb-command:print nested_non_zero_yep -// gdb-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {10.5, {a = 10, b = 20, c = [...]}}} +// gdb-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}} // gdb-command:print nested_non_zero_nope -// gdb-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {[...], {a = [...], b = [...], c = 0x0}}} +// gdb-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}} // gdb-command:continue diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 16ae83ee8d..7b337ba2cc 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -10,33 +10,33 @@ // Need a fix for LLDB first... // ignore-lldb - +// ignore-tidy-linelength // compile-flags:-g // gdb-command:run // gdb-command:print/d vi8x16 -// gdb-check:$1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} +// gdb-check:$1 = {__0 = 0, __1 = 1, __2 = 2, __3 = 3, __4 = 4, __5 = 5, __6 = 6, __7 = 7, __8 = 8, __9 = 9, __10 = 10, __11 = 11, __12 = 12, __13 = 13, __14 = 14, __15 = 15} // gdb-command:print/d vi16x8 -// gdb-check:$2 = {16, 17, 18, 19, 20, 21, 22, 23} +// gdb-check:$2 = {__0 = 16, __1 = 17, __2 = 18, __3 = 19, __4 = 20, __5 = 21, __6 = 22, __7 = 23} // gdb-command:print/d vi32x4 -// gdb-check:$3 = {24, 25, 26, 27} +// gdb-check:$3 = {__0 = 24, __1 = 25, __2 = 26, __3 = 27} // gdb-command:print/d vi64x2 -// gdb-check:$4 = {28, 29} +// gdb-check:$4 = {__0 = 28, __1 = 29} // gdb-command:print/d vu8x16 -// gdb-check:$5 = {30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45} +// gdb-check:$5 = {__0 = 30, __1 = 31, __2 = 32, __3 = 33, __4 = 34, __5 = 35, __6 = 36, __7 = 37, __8 = 38, __9 = 39, __10 = 40, __11 = 41, __12 = 42, __13 = 43, __14 = 44, __15 = 45} // gdb-command:print/d vu16x8 -// gdb-check:$6 = {46, 47, 48, 49, 50, 51, 52, 53} +// gdb-check:$6 = {__0 = 46, __1 = 47, __2 = 48, __3 = 49, __4 = 50, __5 = 51, __6 = 52, __7 = 53} // gdb-command:print/d vu32x4 -// gdb-check:$7 = {54, 55, 56, 57} +// gdb-check:$7 = {__0 = 54, __1 = 55, __2 = 56, __3 = 57} // gdb-command:print/d vu64x2 -// gdb-check:$8 = {58, 59} +// gdb-check:$8 = {__0 = 58, __1 = 59} // gdb-command:print vf32x4 -// gdb-check:$9 = {60.5, 61.5, 62.5, 63.5} +// gdb-check:$9 = {__0 = 60.5, __1 = 61.5, __2 = 62.5, __3 = 63.5} // gdb-command:print vf64x2 -// gdb-check:$10 = {64.5, 65.5} +// gdb-check:$10 = {__0 = 64.5, __1 = 65.5} // gdb-command:continue diff --git a/src/test/debuginfo/simple-tuple.rs b/src/test/debuginfo/simple-tuple.rs index 3c3a85a34c..29bf9c5e41 100644 --- a/src/test/debuginfo/simple-tuple.rs +++ b/src/test/debuginfo/simple-tuple.rs @@ -15,57 +15,57 @@ // === GDB TESTS =================================================================================== // gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$1 = {-50, 50} +// gdb-check:$1 = {__0 = -50, __1 = 50} // gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$2 = {-1, 2, 3} +// gdb-check:$2 = {__0 = -1, __1 = 2, __2 = 3} // gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$3 = {4, 5, 6} +// gdb-check:$3 = {__0 = 4, __1 = 5, __2 = 6} // gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$4 = {7, 8, 9} +// gdb-check:$4 = {__0 = 7, __1 = 8, __2 = 9} // gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$5 = {10, 11} +// gdb-check:$5 = {__0 = 10, __1 = 11} // gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$6 = {12, 13, 14, 15} +// gdb-check:$6 = {__0 = 12, __1 = 13, __2 = 14, __3 = 15} // gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$7 = {16, 17} +// gdb-check:$7 = {__0 = 16, __1 = 17} // gdb-command:run // gdb-command:print/d noPadding8 -// gdb-check:$8 = {-100, 100} +// gdb-check:$8 = {__0 = -100, __1 = 100} // gdb-command:print noPadding16 -// gdb-check:$9 = {0, 1, 2} +// gdb-check:$9 = {__0 = 0, __1 = 1, __2 = 2} // gdb-command:print noPadding32 -// gdb-check:$10 = {3, 4.5, 5} +// gdb-check:$10 = {__0 = 3, __1 = 4.5, __2 = 5} // gdb-command:print noPadding64 -// gdb-check:$11 = {6, 7.5, 8} +// gdb-check:$11 = {__0 = 6, __1 = 7.5, __2 = 8} // gdb-command:print internalPadding1 -// gdb-check:$12 = {9, 10} +// gdb-check:$12 = {__0 = 9, __1 = 10} // gdb-command:print internalPadding2 -// gdb-check:$13 = {11, 12, 13, 14} +// gdb-check:$13 = {__0 = 11, __1 = 12, __2 = 13, __3 = 14} // gdb-command:print paddingAtEnd -// gdb-check:$14 = {15, 16} +// gdb-check:$14 = {__0 = 15, __1 = 16} // gdb-command:print/d 'simple_tuple::NO_PADDING_8' -// gdb-check:$15 = {-127, 127} +// gdb-check:$15 = {__0 = -127, __1 = 127} // gdb-command:print 'simple_tuple::NO_PADDING_16' -// gdb-check:$16 = {-10, 10, 9} +// gdb-check:$16 = {__0 = -10, __1 = 10, __2 = 9} // gdb-command:print 'simple_tuple::NO_PADDING_32' -// gdb-check:$17 = {14, 15, 16} +// gdb-check:$17 = {__0 = 14, __1 = 15, __2 = 16} // gdb-command:print 'simple_tuple::NO_PADDING_64' -// gdb-check:$18 = {17, 18, 19} +// gdb-check:$18 = {__0 = 17, __1 = 18, __2 = 19} // gdb-command:print 'simple_tuple::INTERNAL_PADDING_1' -// gdb-check:$19 = {110, 111} +// gdb-check:$19 = {__0 = 110, __1 = 111} // gdb-command:print 'simple_tuple::INTERNAL_PADDING_2' -// gdb-check:$20 = {112, 113, 114, 115} +// gdb-check:$20 = {__0 = 112, __1 = 113, __2 = 114, __3 = 115} // gdb-command:print 'simple_tuple::PADDING_AT_END' -// gdb-check:$21 = {116, 117} +// gdb-check:$21 = {__0 = 116, __1 = 117} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/struct-in-enum.rs b/src/test/debuginfo/struct-in-enum.rs index b7956c2212..e200a497f5 100644 --- a/src/test/debuginfo/struct-in-enum.rs +++ b/src/test/debuginfo/struct-in-enum.rs @@ -19,13 +19,13 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, 0, {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, 0, 8970181431921507452, 31868}} +// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = {x = 2088533116, y = 2088533116, z = 31868}}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452, __2 = 31868}} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, 0, {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, 0, 1229782938247303441, 4369}} +// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = {x = 286331153, y = 286331153, z = 4369}}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441, __2 = 4369}} // gdb-command:print univariant -// gdb-check:$3 = {{{x = 123, y = 456, z = 789}}} +// gdb-check:$3 = {{__0 = {x = 123, y = 456, z = 789}}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-in-struct.rs b/src/test/debuginfo/tuple-in-struct.rs index 7da1ef2e11..04119956f1 100644 --- a/src/test/debuginfo/tuple-in-struct.rs +++ b/src/test/debuginfo/tuple-in-struct.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + // min-lldb-version: 310 // compile-flags:-g @@ -15,29 +17,29 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {x = {0, 1}, y = 2, z = {3, 4, 5}} +// gdb-check:$1 = {x = {__0 = 0, __1 = 1}, y = 2, z = {__0 = 3, __1 = 4, __2 = 5}} // gdb-command:print no_padding2 -// gdb-check:$2 = {x = {6, 7}, y = {{8, 9}, 10}} +// gdb-check:$2 = {x = {__0 = 6, __1 = 7}, y = {__0 = {__0 = 8, __1 = 9}, __1 = 10}} // gdb-command:print tuple_internal_padding -// gdb-check:$3 = {x = {11, 12}, y = {13, 14}} +// gdb-check:$3 = {x = {__0 = 11, __1 = 12}, y = {__0 = 13, __1 = 14}} // gdb-command:print struct_internal_padding -// gdb-check:$4 = {x = {15, 16}, y = {17, 18}} +// gdb-check:$4 = {x = {__0 = 15, __1 = 16}, y = {__0 = 17, __1 = 18}} // gdb-command:print both_internally_padded -// gdb-check:$5 = {x = {19, 20, 21}, y = {22, 23}} +// gdb-check:$5 = {x = {__0 = 19, __1 = 20, __2 = 21}, y = {__0 = 22, __1 = 23}} // gdb-command:print single_tuple -// gdb-check:$6 = {x = {24, 25, 26}} +// gdb-check:$6 = {x = {__0 = 24, __1 = 25, __2 = 26}} // gdb-command:print tuple_padded_at_end -// gdb-check:$7 = {x = {27, 28}, y = {29, 30}} +// gdb-check:$7 = {x = {__0 = 27, __1 = 28}, y = {__0 = 29, __1 = 30}} // gdb-command:print struct_padded_at_end -// gdb-check:$8 = {x = {31, 32}, y = {33, 34}} +// gdb-check:$8 = {x = {__0 = 31, __1 = 32}, y = {__0 = 33, __1 = 34}} // gdb-command:print both_padded_at_end -// gdb-check:$9 = {x = {35, 36, 37}, y = {38, 39}} +// gdb-check:$9 = {x = {__0 = 35, __1 = 36, __2 = 37}, y = {__0 = 38, __1 = 39}} // gdb-command:print mixed_padding -// gdb-check:$10 = {x = {{40, 41, 42}, {43, 44}}, y = {45, 46, 47, 48}} +// gdb-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}} #![allow(unused_variables)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/tuple-in-tuple.rs b/src/test/debuginfo/tuple-in-tuple.rs index 9b4c759ab0..e981091303 100644 --- a/src/test/debuginfo/tuple-in-tuple.rs +++ b/src/test/debuginfo/tuple-in-tuple.rs @@ -17,21 +17,21 @@ // gdb-command:run // gdb-command:print no_padding1 -// gdb-check:$1 = {{0, 1}, 2, 3} +// gdb-check:$1 = {__0 = {__0 = 0, __1 = 1}, __1 = 2, __2 = 3} // gdb-command:print no_padding2 -// gdb-check:$2 = {4, {5, 6}, 7} +// gdb-check:$2 = {__0 = 4, __1 = {__0 = 5, __1 = 6}, __2 = 7} // gdb-command:print no_padding3 -// gdb-check:$3 = {8, 9, {10, 11}} +// gdb-check:$3 = {__0 = 8, __1 = 9, __2 = {__0 = 10, __1 = 11}} // gdb-command:print internal_padding1 -// gdb-check:$4 = {12, {13, 14}} +// gdb-check:$4 = {__0 = 12, __1 = {__0 = 13, __1 = 14}} // gdb-command:print internal_padding2 -// gdb-check:$5 = {15, {16, 17}} +// gdb-check:$5 = {__0 = 15, __1 = {__0 = 16, __1 = 17}} // gdb-command:print padding_at_end1 -// gdb-check:$6 = {18, {19, 20}} +// gdb-check:$6 = {__0 = 18, __1 = {__0 = 19, __1 = 20}} // gdb-command:print padding_at_end2 -// gdb-check:$7 = {{21, 22}, 23} +// gdb-check:$7 = {__0 = {__0 = 21, __1 = 22}, __1 = 23} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-struct.rs b/src/test/debuginfo/tuple-struct.rs index e679dac954..5e4e849457 100644 --- a/src/test/debuginfo/tuple-struct.rs +++ b/src/test/debuginfo/tuple-struct.rs @@ -17,22 +17,22 @@ // gdb-command:run // gdb-command:print no_padding16 -// gdb-check:$1 = {10000, -10001} +// gdb-check:$1 = {__0 = 10000, __1 = -10001} // gdb-command:print no_padding32 -// gdb-check:$2 = {-10002, -10003.5, 10004} +// gdb-check:$2 = {__0 = -10002, __1 = -10003.5, __2 = 10004} // gdb-command:print no_padding64 -// gdb-check:$3 = {-10005.5, 10006, 10007} +// gdb-check:$3 = {__0 = -10005.5, __1 = 10006, __2 = 10007} // gdb-command:print no_padding163264 -// gdb-check:$4 = {-10008, 10009, 10010, 10011} +// gdb-check:$4 = {__0 = -10008, __1 = 10009, __2 = 10010, __3 = 10011} // gdb-command:print internal_padding -// gdb-check:$5 = {10012, -10013} +// gdb-check:$5 = {__0 = 10012, __1 = -10013} // gdb-command:print padding_at_end -// gdb-check:$6 = {-10014, 10015} +// gdb-check:$6 = {__0 = -10014, __1 = 10015} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/tuple-style-enum.rs b/src/test/debuginfo/tuple-style-enum.rs index 6ed231726b..48c47c5115 100644 --- a/src/test/debuginfo/tuple-style-enum.rs +++ b/src/test/debuginfo/tuple-style-enum.rs @@ -19,16 +19,16 @@ // gdb-command:run // gdb-command:print case1 -// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, 0, 31868, 31868, 31868, 31868}, {RUST$ENUM$DISR = Case1, 0, 2088533116, 2088533116}, {RUST$ENUM$DISR = Case1, 0, 8970181431921507452}} +// gdb-check:$1 = {{RUST$ENUM$DISR = Case1, __0 = 0, __1 = 31868, __2 = 31868, __3 = 31868, __4 = 31868}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 2088533116, __2 = 2088533116}, {RUST$ENUM$DISR = Case1, __0 = 0, __1 = 8970181431921507452}} // gdb-command:print case2 -// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, 0, 4369, 4369, 4369, 4369}, {RUST$ENUM$DISR = Case2, 0, 286331153, 286331153}, {RUST$ENUM$DISR = Case2, 0, 1229782938247303441}} +// gdb-check:$2 = {{RUST$ENUM$DISR = Case2, __0 = 0, __1 = 4369, __2 = 4369, __3 = 4369, __4 = 4369}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 286331153, __2 = 286331153}, {RUST$ENUM$DISR = Case2, __0 = 0, __1 = 1229782938247303441}} // gdb-command:print case3 -// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, 0, 22873, 22873, 22873, 22873}, {RUST$ENUM$DISR = Case3, 0, 1499027801, 1499027801}, {RUST$ENUM$DISR = Case3, 0, 6438275382588823897}} +// gdb-check:$3 = {{RUST$ENUM$DISR = Case3, __0 = 0, __1 = 22873, __2 = 22873, __3 = 22873, __4 = 22873}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 1499027801, __2 = 1499027801}, {RUST$ENUM$DISR = Case3, __0 = 0, __1 = 6438275382588823897}} // gdb-command:print univariant -// gdb-check:$4 = {{-1}} +// gdb-check:$4 = {{__0 = -1}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index e450ead009..0252e3b54f 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -18,13 +18,13 @@ // gdb-command:run // gdb-command:print *the_a -// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, 0, 2088533116, 2088533116}} +// gdb-check:$1 = {{RUST$ENUM$DISR = TheA, x = 0, y = 8970181431921507452}, {RUST$ENUM$DISR = TheA, __0 = 0, __1 = 2088533116, __2 = 2088533116}} // gdb-command:print *the_b -// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, 0, 286331153, 286331153}} +// gdb-check:$2 = {{RUST$ENUM$DISR = TheB, x = 0, y = 1229782938247303441}, {RUST$ENUM$DISR = TheB, __0 = 0, __1 = 286331153, __2 = 286331153}} // gdb-command:print *univariant -// gdb-check:$3 = {{123234}} +// gdb-check:$3 = {{__0 = 123234}} // === LLDB TESTS ================================================================================== diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs index 3759082db2..b87a9250f4 100644 --- a/src/test/debuginfo/vec-slices.rs +++ b/src/test/debuginfo/vec-slices.rs @@ -38,9 +38,9 @@ // gdb-command:print padded_tuple.length // gdb-check:$8 = 2 // gdb-command:print padded_tuple.data_ptr[0] -// gdb-check:$9 = {6, 7} +// gdb-check:$9 = {__0 = 6, __1 = 7} // gdb-command:print padded_tuple.data_ptr[1] -// gdb-check:$10 = {8, 9} +// gdb-check:$10 = {__0 = 8, __1 = 9} // gdb-command:print padded_struct.length // gdb-check:$11 = 2 diff --git a/src/test/parse-fail/issue-22647.rs b/src/test/parse-fail/issue-22647.rs index 5de8627001..1ace57edba 100644 --- a/src/test/parse-fail/issue-22647.rs +++ b/src/test/parse-fail/issue-22647.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let caller = |f: F| //~ ERROR unexpected token: `<` + let caller = |f: F| //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` where F: Fn() -> i32 { let x = f(); diff --git a/src/test/parse-fail/issue-22712.rs b/src/test/parse-fail/issue-22712.rs index abc9e59946..ed936cdd9a 100644 --- a/src/test/parse-fail/issue-22712.rs +++ b/src/test/parse-fail/issue-22712.rs @@ -13,7 +13,7 @@ struct Foo { } fn bar() { - let Foo> //~ ERROR unexpected token: `<` + let Foo> //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `<` } fn main() {} diff --git a/src/test/parse-fail/issue-24197.rs b/src/test/parse-fail/issue-24197.rs new file mode 100644 index 0000000000..37d6218261 --- /dev/null +++ b/src/test/parse-fail/issue-24197.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + let buf[0] = 0; //~ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` +} diff --git a/src/test/parse-fail/issue-24375.rs b/src/test/parse-fail/issue-24375.rs new file mode 100644 index 0000000000..8723423325 --- /dev/null +++ b/src/test/parse-fail/issue-24375.rs @@ -0,0 +1,19 @@ +// 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. + +static tmp : [&'static str; 2] = ["hello", "he"]; + +fn main() { + let z = "hello"; + match z { + tmp[0] => {} //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `[` + _ => {} + } +} diff --git a/src/test/parse-fail/issue-5806.rs b/src/test/parse-fail/issue-5806.rs index 09de97d71b..5d2908b92e 100644 --- a/src/test/parse-fail/issue-5806.rs +++ b/src/test/parse-fail/issue-5806.rs @@ -11,6 +11,7 @@ // ignore-windows // ignore-freebsd // ignore-openbsd +// ignore-bitrig #[path = "../compile-fail"] mod foo; //~ ERROR: a directory diff --git a/src/test/parse-fail/match-vec-invalid.rs b/src/test/parse-fail/match-vec-invalid.rs index 3e073d34f3..0fc00c3507 100644 --- a/src/test/parse-fail/match-vec-invalid.rs +++ b/src/test/parse-fail/match-vec-invalid.rs @@ -11,7 +11,7 @@ fn main() { let a = Vec::new(); match a { - [1, tail.., tail..] => {}, //~ ERROR: expected one of `!`, `,`, or `@`, found `..` + [1, tail.., tail..] => {}, //~ ERROR: expected one of `,` or `@`, found `..` _ => () } } diff --git a/src/test/parse-fail/omitted-arg-in-item-fn.rs b/src/test/parse-fail/omitted-arg-in-item-fn.rs index 729b45df8b..2826d3b4af 100644 --- a/src/test/parse-fail/omitted-arg-in-item-fn.rs +++ b/src/test/parse-fail/omitted-arg-in-item-fn.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(x) { //~ ERROR expected one of `!`, `:`, or `@`, found `)` +fn foo(x) { //~ ERROR expected one of `:` or `@`, found `)` } diff --git a/src/test/compile-fail/issue-22426-1.rs b/src/test/parse-fail/pat-lt-bracket-1.rs similarity index 88% rename from src/test/compile-fail/issue-22426-1.rs rename to src/test/parse-fail/pat-lt-bracket-1.rs index f026a5db55..6d3d120778 100644 --- a/src/test/compile-fail/issue-22426-1.rs +++ b/src/test/parse-fail/pat-lt-bracket-1.rs @@ -11,7 +11,7 @@ fn main() { match 42 { x < 7 => (), - //~^ error: unexpected token: `<` + //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` _ => () } } diff --git a/src/test/parse-fail/pat-lt-bracket-2.rs b/src/test/parse-fail/pat-lt-bracket-2.rs new file mode 100644 index 0000000000..6a0653041d --- /dev/null +++ b/src/test/parse-fail/pat-lt-bracket-2.rs @@ -0,0 +1,12 @@ +// 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. + +fn a(B<) {} + //~^ error: expected one of `:` or `@`, found `<` diff --git a/src/test/compile-fail/issue-22426-3.rs b/src/test/parse-fail/pat-lt-bracket-3.rs similarity index 89% rename from src/test/compile-fail/issue-22426-3.rs rename to src/test/parse-fail/pat-lt-bracket-3.rs index 2e0b5d6b80..8ea2bcf900 100644 --- a/src/test/compile-fail/issue-22426-3.rs +++ b/src/test/parse-fail/pat-lt-bracket-3.rs @@ -14,7 +14,7 @@ impl Foo { fn foo(&self) { match *self { Foo(x, y) => { - //~^ error: unexpected token: `<` + //~^ error: expected one of `=>`, `@`, `if`, or `|`, found `<` println!("Goodbye, World!") } } diff --git a/src/test/parse-fail/pat-lt-bracket-4.rs b/src/test/parse-fail/pat-lt-bracket-4.rs new file mode 100644 index 0000000000..3d9b492307 --- /dev/null +++ b/src/test/parse-fail/pat-lt-bracket-4.rs @@ -0,0 +1,21 @@ +// 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. + +enum BtNode { + Node(u32,Box,Box), + Leaf(u32), +} + +fn main() { + let y = match x { + Foo::A(value) => value, //~ error: expected one of `=>`, `@`, `if`, or `|`, found `<` + Foo::B => 7, + }; +} diff --git a/src/test/parse-fail/pat-lt-bracket-5.rs b/src/test/parse-fail/pat-lt-bracket-5.rs new file mode 100644 index 0000000000..3345845eee --- /dev/null +++ b/src/test/parse-fail/pat-lt-bracket-5.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + let v[0] = v[1]; //~ error: expected one of `:`, `;`, `=`, or `@`, found `[` +} diff --git a/src/test/parse-fail/pat-lt-bracket-6.rs b/src/test/parse-fail/pat-lt-bracket-6.rs new file mode 100644 index 0000000000..72fdae8226 --- /dev/null +++ b/src/test/parse-fail/pat-lt-bracket-6.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + let Test(&desc[..]) = x; //~ error: expected one of `,` or `@`, found `[` +} diff --git a/src/test/parse-fail/pat-lt-bracket-7.rs b/src/test/parse-fail/pat-lt-bracket-7.rs new file mode 100644 index 0000000000..c7731d156a --- /dev/null +++ b/src/test/parse-fail/pat-lt-bracket-7.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + for thing(x[]) {} //~ error: expected one of `,` or `@`, found `[` +} diff --git a/src/test/parse-fail/pat-ranges-1.rs b/src/test/parse-fail/pat-ranges-1.rs new file mode 100644 index 0000000000..e1cbb961b1 --- /dev/null +++ b/src/test/parse-fail/pat-ranges-1.rs @@ -0,0 +1,15 @@ +// 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. + +// Parsing of range patterns + +fn main() { + let macropus!() ... 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `...` +} diff --git a/src/test/parse-fail/pat-ranges-2.rs b/src/test/parse-fail/pat-ranges-2.rs new file mode 100644 index 0000000000..04ad5ff083 --- /dev/null +++ b/src/test/parse-fail/pat-ranges-2.rs @@ -0,0 +1,15 @@ +// 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. + +// Parsing of range patterns + +fn main() { + let 10 ... makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` +} diff --git a/src/test/parse-fail/pat-ranges-3.rs b/src/test/parse-fail/pat-ranges-3.rs new file mode 100644 index 0000000000..5f7aac71d2 --- /dev/null +++ b/src/test/parse-fail/pat-ranges-3.rs @@ -0,0 +1,15 @@ +// 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. + +// Parsing of range patterns + +fn main() { + let 10 ... 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` +} diff --git a/src/test/parse-fail/pat-ranges-4.rs b/src/test/parse-fail/pat-ranges-4.rs new file mode 100644 index 0000000000..50dcb89952 --- /dev/null +++ b/src/test/parse-fail/pat-ranges-4.rs @@ -0,0 +1,15 @@ +// 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. + +// Parsing of range patterns + +fn main() { + let 10 - 3 ... 10 = 8; //~ error: expected one of `...`, `:`, `;`, or `=`, found `-` +} diff --git a/src/test/parse-fail/removed-syntax-larrow-init.rs b/src/test/parse-fail/removed-syntax-larrow-init.rs index 1474cc9dd3..116848c42c 100644 --- a/src/test/parse-fail/removed-syntax-larrow-init.rs +++ b/src/test/parse-fail/removed-syntax-larrow-init.rs @@ -11,5 +11,5 @@ fn removed_moves() { let mut x = 0; let y <- x; - //~^ ERROR expected one of `!`, `:`, `;`, `=`, or `@`, found `<-` + //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `<-` } diff --git a/src/test/parse-fail/struct-literal-in-match-discriminant.rs b/src/test/parse-fail/struct-literal-in-match-discriminant.rs index cdcf98a42f..85addc8229 100644 --- a/src/test/parse-fail/struct-literal-in-match-discriminant.rs +++ b/src/test/parse-fail/struct-literal-in-match-discriminant.rs @@ -14,7 +14,7 @@ struct Foo { fn main() { match Foo { - x: 3 //~ ERROR expected one of `!`, `=>`, `@`, `if`, or `|`, found `:` + x: 3 //~ ERROR expected one of `=>`, `@`, `if`, or `|`, found `:` } { Foo { x: x diff --git a/src/test/parse-fail/wrong-escape-of-curly-braces.rs b/src/test/parse-fail/wrong-escape-of-curly-braces.rs new file mode 100644 index 0000000000..d86bf726cb --- /dev/null +++ b/src/test/parse-fail/wrong-escape-of-curly-braces.rs @@ -0,0 +1,18 @@ +// 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. + +fn f() { + let ok = "{{everything fine}}"; + let bad = "\{it is wrong\}"; + //~^ ERROR unknown character escape: { + //~^^ HELP if used in a formatting string, curly braces are escaped with `{{` and `}}` + //~^^^ ERROR unknown character escape: } + //~^^^^ HELP if used in a formatting string, curly braces are escaped with `{{` and `}}` +} diff --git a/src/test/pretty/default-trait-impl.rs b/src/test/pretty/default-trait-impl.rs index 509bee9def..a5246b9300 100644 --- a/src/test/pretty/default-trait-impl.rs +++ b/src/test/pretty/default-trait-impl.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(optin_builtin_traits, core)] +#![feature(optin_builtin_traits)] // pp-exact -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait { } +trait MyTrait { } impl MyTrait for .. { } diff --git a/src/test/run-fail/diverging-closure.rs b/src/test/run-fail/diverging-closure.rs new file mode 100644 index 0000000000..6b98e0397b --- /dev/null +++ b/src/test/run-fail/diverging-closure.rs @@ -0,0 +1,18 @@ +// 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. + +// error-pattern:oops + +fn main() { + let func = || -> ! { + panic!("oops"); + }; + func(); +} diff --git a/src/test/run-fail/overflowing-neg.rs b/src/test/run-fail/overflowing-neg.rs new file mode 100644 index 0000000000..cdb74c7d7e --- /dev/null +++ b/src/test/run-fail/overflowing-neg.rs @@ -0,0 +1,19 @@ +// 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. + +// error-pattern:thread '

' panicked at 'attempted to negate with overflow' +// compile-flags: -C debug-assertions + +// (Work around constant-evaluation) +fn value() -> i8 { std::i8::MIN } + +fn main() { + let _x = -value(); +} diff --git a/src/test/run-fail/panic-task-name-owned.rs b/src/test/run-fail/panic-task-name-owned.rs index 8cab9e05f9..561f141100 100644 --- a/src/test/run-fail/panic-task-name-owned.rs +++ b/src/test/run-fail/panic-task-name-owned.rs @@ -13,9 +13,9 @@ use std::thread::Builder; fn main() { - let r: () = Builder::new().name("owned name".to_string()).scoped(move|| { + let r: () = Builder::new().name("owned name".to_string()).spawn(move|| { panic!("test"); () - }).unwrap().join(); + }).unwrap().join().unwrap(); panic!(); } diff --git a/src/test/run-fail/rt-set-exit-status-panic2.rs b/src/test/run-fail/rt-set-exit-status-panic2.rs index fddff3c5a9..b4f0d7ceb9 100644 --- a/src/test/run-fail/rt-set-exit-status-panic2.rs +++ b/src/test/run-fail/rt-set-exit-status-panic2.rs @@ -37,7 +37,7 @@ fn r(x:isize) -> r { fn main() { error!("whatever"); - let _t = thread::scoped(move|| { + let _t = thread::spawn(move|| { let _i = r(5); }); panic!(); diff --git a/src/test/run-make/c-link-to-rust-staticlib/Makefile b/src/test/run-make/c-link-to-rust-staticlib/Makefile index 477b85f362..56c09b895f 100644 --- a/src/test/run-make/c-link-to-rust-staticlib/Makefile +++ b/src/test/run-make/c-link-to-rust-staticlib/Makefile @@ -8,7 +8,7 @@ endif ifneq ($(shell uname),FreeBSD) all: $(RUSTC) foo.rs - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) -lstdc++ + $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) $(EXTRACXXFLAGS) $(call RUN,bar) rm $(call STATICLIB,foo*) $(call RUN,bar) diff --git a/src/test/run-make/include_bytes_deps/Makefile b/src/test/run-make/include_bytes_deps/Makefile new file mode 100644 index 0000000000..0400db412d --- /dev/null +++ b/src/test/run-make/include_bytes_deps/Makefile @@ -0,0 +1,21 @@ +-include ../tools.mk + +# FIXME: ignore freebsd/windows +# on windows `rustc --dep-info` produces Makefile dependency with +# windows native paths (e.g. `c:\path\to\libfoo.a`) +# but msys make seems to fail to recognize such paths, so test fails. +ifneq ($(shell uname),FreeBSD) +ifndef IS_WINDOWS +all: + $(RUSTC) --emit dep-info main.rs + grep "input.txt" $(TMPDIR)/main.d + grep "input.bin" $(TMPDIR)/main.d +else +all: + +endif + +else +all: + +endif diff --git a/src/test/run-make/include_bytes_deps/input.bin b/src/test/run-make/include_bytes_deps/input.bin new file mode 100644 index 0000000000..cd0875583a --- /dev/null +++ b/src/test/run-make/include_bytes_deps/input.bin @@ -0,0 +1 @@ +Hello world! diff --git a/src/test/run-make/include_bytes_deps/input.txt b/src/test/run-make/include_bytes_deps/input.txt new file mode 100644 index 0000000000..cd0875583a --- /dev/null +++ b/src/test/run-make/include_bytes_deps/input.txt @@ -0,0 +1 @@ +Hello world! diff --git a/src/libstd/sys/unix/udp.rs b/src/test/run-make/include_bytes_deps/main.rs similarity index 68% rename from src/libstd/sys/unix/udp.rs rename to src/test/run-make/include_bytes_deps/main.rs index 50f8fb828a..579b2a452a 100644 --- a/src/libstd/sys/unix/udp.rs +++ b/src/test/run-make/include_bytes_deps/main.rs @@ -8,4 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use sys_common::net::UdpSocket; +pub fn main() { + const INPUT_TXT: &'static str = include_str!("input.txt"); + const INPUT_BIN: &'static [u8] = include_bytes!("input.bin"); + + println!("{}", INPUT_TXT); + println!("{:?}", INPUT_BIN); +} diff --git a/src/test/run-make/issue-14500/Makefile b/src/test/run-make/issue-14500/Makefile index c19d3d5c30..6ea3cf48ff 100644 --- a/src/test/run-make/issue-14500/Makefile +++ b/src/test/run-make/issue-14500/Makefile @@ -6,6 +6,10 @@ # is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the # only way that `foo.c` will successfully compile. +ifeq ($(UNAME),Bitrig) + EXTRACFLAGS := -lc $(EXTRACFLAGS) $(EXTRACXXFLAGS) +endif + all: $(RUSTC) foo.rs --crate-type=rlib $(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a diff --git a/src/test/run-make/issue-22131/foo.rs b/src/test/run-make/issue-22131/foo.rs index 0b1f1291df..50c63abc0d 100644 --- a/src/test/run-make/issue-22131/foo.rs +++ b/src/test/run-make/issue-22131/foo.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_name="foo"] - /// ```rust /// assert_eq!(foo::foo(), 1); /// ``` diff --git a/src/test/run-make/issue-24445/Makefile b/src/test/run-make/issue-24445/Makefile new file mode 100644 index 0000000000..7a0cbfcf51 --- /dev/null +++ b/src/test/run-make/issue-24445/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +ifeq ($(UNAME),Linux) +all: + $(RUSTC) foo.rs + $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -o $(TMPDIR)/foo + $(call RUN,foo) + $(CC) foo.c -lfoo -L $(TMPDIR) -Wl,--gc-sections -lpthread -pie -fPIC -o $(TMPDIR)/foo + $(call RUN,foo) +else +all: +endif diff --git a/src/test/run-make/rustdoc-default-impl/bar.rs b/src/test/run-make/issue-24445/foo.c similarity index 87% rename from src/test/run-make/rustdoc-default-impl/bar.rs rename to src/test/run-make/issue-24445/foo.c index 60a2f7202f..775e151f23 100644 --- a/src/test/run-make/rustdoc-default-impl/bar.rs +++ b/src/test/run-make/issue-24445/foo.c @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern crate foo; +void foo(); -pub use foo::bar; - -pub fn wut() { +int main() { + foo(); + return 0; } diff --git a/src/test/run-make/issue-24445/foo.rs b/src/test/run-make/issue-24445/foo.rs new file mode 100644 index 0000000000..65e505df5e --- /dev/null +++ b/src/test/run-make/issue-24445/foo.rs @@ -0,0 +1,25 @@ +// 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. + +#![crate_type = "staticlib"] + +struct Destroy; +impl Drop for Destroy { + fn drop(&mut self) { println!("drop"); } +} + +thread_local! { + static X: Destroy = Destroy +} + +#[no_mangle] +pub extern "C" fn foo() { + X.with(|_| ()); +} diff --git a/src/test/run-make/lto-smoke-c/Makefile b/src/test/run-make/lto-smoke-c/Makefile index c678a3c472..6165afbeb2 100644 --- a/src/test/run-make/lto-smoke-c/Makefile +++ b/src/test/run-make/lto-smoke-c/Makefile @@ -5,5 +5,5 @@ CC := $(CC:-g=) all: $(RUSTC) foo.rs -C lto - $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) -lstdc++ + $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) $(EXTRACXXFLAGS) $(call RUN,bar) diff --git a/src/test/run-make/no-stack-check/Makefile b/src/test/run-make/no-stack-check/Makefile index 5fce35e2be..a2e1fe5627 100644 --- a/src/test/run-make/no-stack-check/Makefile +++ b/src/test/run-make/no-stack-check/Makefile @@ -1,7 +1,11 @@ -include ../tools.mk + ifndef IS_WINDOWS -ifneq ($(UNAME),OpenBSD) + +SKIP_OS := 'OpenBSD Bitrig' +ifneq ($(UNAME),$(findstring $(UNAME),$(SKIP_OS))) + all: $(RUSTC) -O --emit asm attr.rs ! grep -q morestack $(TMPDIR)/attr.s @@ -10,9 +14,10 @@ all: $(RUSTC) -O --emit asm -C no-stack-check flag.rs ! grep -q morestack $(TMPDIR)/flag.s else -# On OpenBSD, morestack isn't used as the segmented stacks are disabled +# On Bitrig/OpenBSD, morestack isn't used as the segmented stacks are disabled all: endif + else # On Windows we use __chkstk and it only appears in functions with large allocations, # so this test wouldn't be reliable. diff --git a/src/test/run-make/rustdoc-assoc-types/Makefile b/src/test/run-make/rustdoc-assoc-types/Makefile deleted file mode 100644 index 74fca83f5f..0000000000 --- a/src/test/run-make/rustdoc-assoc-types/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: lib.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs - $(HTMLDOCCK) $(TMPDIR)/doc lib.rs diff --git a/src/test/run-make/rustdoc-default-impl/Makefile b/src/test/run-make/rustdoc-default-impl/Makefile deleted file mode 100644 index 338cf9d205..0000000000 --- a/src/test/run-make/rustdoc-default-impl/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: foo.rs bar.rs - $(RUSTC) foo.rs --crate-type lib - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc bar.rs -L $(TMPDIR) diff --git a/src/test/run-make/rustdoc-extern-default-method/Makefile b/src/test/run-make/rustdoc-extern-default-method/Makefile deleted file mode 100644 index ffc4a08f80..0000000000 --- a/src/test/run-make/rustdoc-extern-default-method/Makefile +++ /dev/null @@ -1,6 +0,0 @@ --include ../tools.mk - -all: lib.rs ext.rs - $(HOST_RPATH_ENV) $(RUSTC) ext.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc lib.rs - $(HTMLDOCCK) $(TMPDIR)/doc lib.rs diff --git a/src/test/run-make/rustdoc-extern-method/Makefile b/src/test/run-make/rustdoc-extern-method/Makefile deleted file mode 100644 index 55cbd2da6a..0000000000 --- a/src/test/run-make/rustdoc-extern-method/Makefile +++ /dev/null @@ -1,7 +0,0 @@ --include ../tools.mk - -all: foo.rs bar.rs - $(HOST_RPATH_ENV) $(RUSTC) foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc bar.rs - $(HTMLDOCCK) $(TMPDIR)/doc bar.rs diff --git a/src/test/run-make/rustdoc-ffi/Makefile b/src/test/run-make/rustdoc-ffi/Makefile deleted file mode 100644 index c312efe12f..0000000000 --- a/src/test/run-make/rustdoc-ffi/Makefile +++ /dev/null @@ -1,8 +0,0 @@ --include ../tools.mk - -all: lib.rs - $(HOST_RPATH_ENV) $(RUSTC) lib.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -L $(TMPDIR) -w html -o $(TMPDIR)/doc user.rs - $(HTMLDOCCK) $(TMPDIR)/doc lib.rs - $(HTMLDOCCK) $(TMPDIR)/doc user.rs diff --git a/src/test/run-make/rustdoc-hidden-line/Makefile b/src/test/run-make/rustdoc-hidden-line/Makefile deleted file mode 100644 index 3ac7b6d2fa..0000000000 --- a/src/test/run-make/rustdoc-hidden-line/Makefile +++ /dev/null @@ -1,15 +0,0 @@ --include ../tools.mk - -# FIXME ignore windows -ifndef IS_WINDOWS - -all: - @echo $(RUSTDOC) - $(HOST_RPATH_ENV) $(RUSTDOC) --test foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs - -else -all: - -endif diff --git a/src/test/run-make/rustdoc-must-use/Makefile b/src/test/run-make/rustdoc-must-use/Makefile deleted file mode 100644 index 74fca83f5f..0000000000 --- a/src/test/run-make/rustdoc-must-use/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: lib.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc lib.rs - $(HTMLDOCCK) $(TMPDIR)/doc lib.rs diff --git a/src/test/run-make/rustdoc-negative-impl/Makefile b/src/test/run-make/rustdoc-negative-impl/Makefile deleted file mode 100644 index c1b1683efd..0000000000 --- a/src/test/run-make/rustdoc-negative-impl/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs diff --git a/src/test/run-make/rustdoc-recursion/Makefile b/src/test/run-make/rustdoc-recursion/Makefile deleted file mode 100644 index ba971836e5..0000000000 --- a/src/test/run-make/rustdoc-recursion/Makefile +++ /dev/null @@ -1,11 +0,0 @@ --include ../tools.mk - -# FIXME ignore windows -ifndef IS_WINDOWS -all: - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo2.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo3.rs -else -all: -endif diff --git a/src/test/run-make/rustdoc-search-index/Makefile b/src/test/run-make/rustdoc-search-index/Makefile deleted file mode 100644 index e7e8f0c35a..0000000000 --- a/src/test/run-make/rustdoc-search-index/Makefile +++ /dev/null @@ -1,15 +0,0 @@ --include ../tools.mk - -# FIXME ignore windows -ifndef IS_WINDOWS - -source=index.rs - -all: - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc $(source) - $(HTMLDOCCK) $(TMPDIR)/doc $(source) - -else -all: - -endif diff --git a/src/test/run-make/rustdoc-smoke/Makefile b/src/test/run-make/rustdoc-smoke/Makefile deleted file mode 100644 index 7a1ad761b3..0000000000 --- a/src/test/run-make/rustdoc-smoke/Makefile +++ /dev/null @@ -1,4 +0,0 @@ --include ../tools.mk -all: - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs diff --git a/src/test/run-make/rustdoc-src-links/Makefile b/src/test/run-make/rustdoc-src-links/Makefile deleted file mode 100644 index 419603e82f..0000000000 --- a/src/test/run-make/rustdoc-src-links/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk -all: - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc qux/mod.rs diff --git a/src/test/run-make/rustdoc-src-links/foo.rs b/src/test/run-make/rustdoc-src-links/foo.rs deleted file mode 100644 index 9a964f1125..0000000000 --- a/src/test/run-make/rustdoc-src-links/foo.rs +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -#![crate_name = "foo"] - -//! Dox -// @has src/foo/foo.rs.html -// @has foo/index.html '//a/@href' '../src/foo/foo.rs.html' - -pub mod qux; - -// @has foo/bar/index.html '//a/@href' '../../src/foo/foo.rs.html' -pub mod bar { - - /// Dox - // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/foo.rs.html' - pub mod baz { - /// Dox - // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/foo.rs.html' - pub fn baz() { } - } - - /// Dox - // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/foo.rs.html' - pub trait Foobar { fn dummy(&self) { } } - - // @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/foo.rs.html' - pub struct Foo { x: i32, y: u32 } - - // @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/foo.rs.html' - pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } -} - -/// Dox -// @has foo/fn.modfn.html '//a/@href' '../src/foo/foo.rs.html' -pub fn modfn() { } diff --git a/src/test/run-make/rustdoc-src-links/qux/mod.rs b/src/test/run-make/rustdoc-src-links/qux/mod.rs deleted file mode 100644 index 9b1563d32a..0000000000 --- a/src/test/run-make/rustdoc-src-links/qux/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -// 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. - -//! Dox -// @has src/foo/qux/mod.rs.html -// @has foo/qux/index.html '//a/@href' '../../src/foo/qux/mod.rs.html' - -// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/qux/mod.rs.html' -pub mod bar { - - /// Dox - // @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/qux/mod.rs.html' - pub mod baz { - /// Dox - // @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/qux/mod.rs.html' - pub fn baz() { } - } - - /// Dox - // @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/qux/mod.rs.html' - pub trait Foobar { fn dummy(&self) { } } - - // @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/qux/mod.rs.html' - pub struct Foo { x: i32, y: u32 } - - // @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/qux/mod.rs.html' - pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } -} - -/// Dox -// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/qux/mod.rs.html' -pub fn modfn() { } diff --git a/src/test/run-make/rustdoc-viewpath-self/Makefile b/src/test/run-make/rustdoc-viewpath-self/Makefile deleted file mode 100644 index c1b1683efd..0000000000 --- a/src/test/run-make/rustdoc-viewpath-self/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs diff --git a/src/test/run-make/rustdoc-where/Makefile b/src/test/run-make/rustdoc-where/Makefile deleted file mode 100644 index c1b1683efd..0000000000 --- a/src/test/run-make/rustdoc-where/Makefile +++ /dev/null @@ -1,5 +0,0 @@ --include ../tools.mk - -all: foo.rs - $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc foo.rs - $(HTMLDOCCK) $(TMPDIR)/doc foo.rs diff --git a/src/test/run-make/save-analysis/SubDir/mod.rs b/src/test/run-make/save-analysis/SubDir/mod.rs index 23b7d8bbf0..fe84db08da 100644 --- a/src/test/run-make/save-analysis/SubDir/mod.rs +++ b/src/test/run-make/save-analysis/SubDir/mod.rs @@ -12,21 +12,18 @@ use sub::sub2 as msalias; use sub::sub2; -use std::old_io::stdio::println; static yy: usize = 25; mod sub { pub mod sub2 { - use std::old_io::stdio::println; pub mod sub3 { - use std::old_io::stdio::println; pub fn hello() { - println("hello from module 3"); + println!("hello from module 3"); } } pub fn hello() { - println("hello from a module"); + println!("hello from a module"); } pub struct nested_struct { diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 9d1ab00359..4d75e58aad 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -10,7 +10,7 @@ #![ crate_name = "test" ] #![allow(unstable)] -#![feature(box_syntax, old_io, rustc_private, core)] +#![feature(box_syntax, rustc_private, core, zero_one)] extern crate graphviz; // A simple rust project @@ -19,15 +19,12 @@ extern crate flate as myflate; use std::collections::{HashMap,HashSet}; use std::cell::RefCell; -use std::old_io::stdio::println; use sub::sub2 as msalias; use sub::sub2; use sub::sub2::nested_struct as sub_struct; -use std::num::Float; -use std::num::cast; -use std::num::{from_int,from_i8,from_i32}; +use std::num::One; use std::mem::size_of; @@ -42,8 +39,7 @@ fn test_alias(i: Option<::Item>) { let s = sub_struct{ field2: 45, }; // import tests - fn foo(x: &Float) {} - let _: Option = from_i32(45); + fn foo(x: &One) {} let x = 42; @@ -61,15 +57,13 @@ fn test_tup_struct(x: TupStruct) -> isize { mod sub { pub mod sub2 { - use std::old_io::stdio::println; pub mod sub3 { - use std::old_io::stdio::println; pub fn hello() { - println("hello from module 3"); + println!("hello from module 3"); } } pub fn hello() { - println("hello from a module"); + println!("hello from a module"); } pub struct nested_struct { @@ -106,7 +100,7 @@ trait SomeTrait: SuperTrait { fn Method(&self, x: u32) -> u32; fn prov(&self, x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); 42 } fn provided_method(&self) -> u32 { @@ -122,7 +116,7 @@ trait SubTrait: SomeTrait { impl SomeTrait for some_fields { fn Method(&self, x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); self.field1 } } @@ -134,7 +128,7 @@ impl SubTrait for some_fields {} impl some_fields { fn stat(x: u32) -> u32 { - println(&x.to_string()); + println!("{}", &x.to_string()); 42 } fn stat2(x: &some_fields) -> u32 { @@ -194,20 +188,20 @@ enum SomeStructEnum { fn matchSomeEnum(val: SomeEnum) { match val { - SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); } - SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); } - SomeEnum::Strings(_, _, s3) => { println(s3); } + SomeEnum::Ints(int1, int2) => { println!("{}", &(int1+int2).to_string()); } + SomeEnum::Floats(float1, float2) => { println!("{}", &(float2*float1).to_string()); } + SomeEnum::Strings(_, _, s3) => { println!("{}", s3); } SomeEnum::MyTypes(mt1, mt2) => { - println(&(mt1.field1 - mt2.field1).to_string()); + println!("{}", &(mt1.field1 - mt2.field1).to_string()); } } } fn matchSomeStructEnum(se: SomeStructEnum) { match se { - SomeStructEnum::EnumStruct{a:a, ..} => println(&a.to_string()), - SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println(&f_2.field1.to_string()), - SomeStructEnum::EnumStruct3{f1, ..} => println(&f1.field1.to_string()), + SomeStructEnum::EnumStruct{a:a, ..} => println!("{}", &a.to_string()), + SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println!("{}", &f_2.field1.to_string()), + SomeStructEnum::EnumStruct3{f1, ..} => println!("{}", &f1.field1.to_string()), } } @@ -215,9 +209,9 @@ fn matchSomeStructEnum(se: SomeStructEnum) { fn matchSomeStructEnum2(se: SomeStructEnum) { use SomeStructEnum::*; match se { - EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()), - EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()), - EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println(&f1.field1.to_string()), + EnumStruct{a: ref aaa, ..} => println!("{}", &aaa.to_string()), + EnumStruct2{f1, f2: f2} => println!("{}", &f1.field1.to_string()), + EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println!("{}", &f1.field1.to_string()), _ => {}, } } @@ -225,22 +219,22 @@ fn matchSomeStructEnum2(se: SomeStructEnum) { fn matchSomeOtherEnum(val: SomeOtherEnum) { use SomeOtherEnum::{SomeConst2, SomeConst3}; match val { - SomeOtherEnum::SomeConst1 => { println("I'm const1."); } - SomeConst2 | SomeConst3 => { println("I'm const2 or const3."); } + SomeOtherEnum::SomeConst1 => { println!("I'm const1."); } + SomeConst2 | SomeConst3 => { println!("I'm const2 or const3."); } } } fn hello((z, a) : (u32, String), ex: X) { SameDir2::hello(43); - println(&yy.to_string()); + println!("{}", &yy.to_string()); let (x, y): (u32, u32) = (5, 3); - println(&x.to_string()); - println(&z.to_string()); + println!("{}", &x.to_string()); + println!("{}", &z.to_string()); let x: u32 = x; - println(&x.to_string()); + println!("{}", &x.to_string()); let x = "hello"; - println(x); + println!("{}", x); let x = 32.0f32; let _ = (x + ((x * x) + 1.0).sqrt()).ln(); @@ -312,7 +306,7 @@ fn main() { // foo let s3: some_fields = some_fields{ field1: 55}; let s4: msalias::nested_struct = sub::sub2::nested_struct{ field2: 55}; let s4: msalias::nested_struct = sub2::nested_struct{ field2: 55}; - println(&s2.field1.to_string()); + println!("{}", &s2.field1.to_string()); let s5: MyType = box some_fields{ field1: 55}; let s = SameDir::SameStruct{name: "Bob".to_string()}; let s = SubDir::SubStruct{name:"Bob".to_string()}; diff --git a/src/test/run-make/simd-ffi/simd.rs b/src/test/run-make/simd-ffi/simd.rs index f418d5d1fb..563fe79e53 100644 --- a/src/test/run-make/simd-ffi/simd.rs +++ b/src/test/run-make/simd-ffi/simd.rs @@ -70,14 +70,10 @@ pub fn bar(a: i32x4, b: i32x4) -> i32x4 { } #[lang = "sized"] -pub trait Sized : PhantomFn {} +pub trait Sized { } #[lang = "copy"] -pub trait Copy : PhantomFn {} - -#[lang="phantom_fn"] -pub trait PhantomFn { } -impl PhantomFn for U { } +pub trait Copy { } mod core { pub mod marker { diff --git a/src/test/run-make/symbols-are-reasonable/lib.rs b/src/test/run-make/symbols-are-reasonable/lib.rs index 8ba705bfb6..ff56ed6286 100644 --- a/src/test/run-make/symbols-are-reasonable/lib.rs +++ b/src/test/run-make/symbols-are-reasonable/lib.rs @@ -16,5 +16,5 @@ impl Foo for usize {} pub fn dummy() { // force the vtable to be created - let _x = &1us as &Foo; + let _x = &1usize as &Foo; } diff --git a/src/test/run-make/target-specs/foo.rs b/src/test/run-make/target-specs/foo.rs index b13c41be55..9dbae19338 100644 --- a/src/test/run-make/target-specs/foo.rs +++ b/src/test/run-make/target-specs/foo.rs @@ -11,15 +11,11 @@ #![feature(lang_items, no_std)] #![no_std] -#[lang="phantom_fn"] -trait PhantomFn { } -impl PhantomFn for U { } - #[lang="copy"] -trait Copy : PhantomFn { } +trait Copy { } #[lang="sized"] -trait Sized : PhantomFn { } +trait Sized { } #[lang="start"] fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 7b604bedfd..223296286b 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -55,15 +55,21 @@ endif ifdef IS_WINDOWS EXTRACFLAGS := -lws2_32 -luserenv else -ifeq ($(shell uname),Darwin) +ifeq ($(UNAME),Darwin) else -ifeq ($(shell uname),FreeBSD) +ifeq ($(UNAME),FreeBSD) EXTRACFLAGS := -lm -lpthread -lgcc_s else -ifeq ($(shell uname),OpenBSD) +ifeq ($(UNAME),Bitrig) + EXTRACFLAGS := -lm -lpthread + EXTRACXXFLAGS := -lc++ -lc++abi +else +ifeq ($(UNAME),OpenBSD) EXTRACFLAGS := -lm -lpthread else EXTRACFLAGS := -lm -lrt -ldl -lpthread + EXTRACXXFLAGS := -lstdc++ +endif endif endif endif diff --git a/src/test/run-make/unicode-input/multiple_files.rs b/src/test/run-make/unicode-input/multiple_files.rs index aa2ce78577..b1fe938767 100644 --- a/src/test/run-make/unicode-input/multiple_files.rs +++ b/src/test/run-make/unicode-input/multiple_files.rs @@ -14,7 +14,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; use std::process::Command; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; use std::{char, env}; // creates unicode_input_multiple_files_{main,chars}.rs, where the diff --git a/src/test/run-make/unicode-input/span_length.rs b/src/test/run-make/unicode-input/span_length.rs index a70a160076..0c01a84d1b 100644 --- a/src/test/run-make/unicode-input/span_length.rs +++ b/src/test/run-make/unicode-input/span_length.rs @@ -15,7 +15,7 @@ use std::io::prelude::*; use std::iter::repeat; use std::path::Path; use std::process::Command; -use std::rand::{thread_rng, Rng}; +use std::__rand::{thread_rng, Rng}; use std::{char, env}; // creates a file with `fn main() { }` and checks the diff --git a/src/test/run-make/use-extern-for-plugins/Makefile b/src/test/run-make/use-extern-for-plugins/Makefile index f8abc5019b..c67bd3d82e 100644 --- a/src/test/run-make/use-extern-for-plugins/Makefile +++ b/src/test/run-make/use-extern-for-plugins/Makefile @@ -1,6 +1,9 @@ -include ../tools.mk -ifneq ($(findstring BSD,$(UNAME)),BSD) +SKIP_OS := 'FreeBSD OpenBSD Bitrig' + +ifneq ($(UNAME),$(findstring $(UNAME),$(SKIP_OS))) + HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //') ifeq ($(findstring i686,$(HOST)),i686) TARGET := $(subst i686,x86_64,$(HOST)) @@ -13,6 +16,6 @@ all: $(RUSTC) bar.rs -C extra-filename=-targ --target $(TARGET) $(RUSTC) baz.rs --extern a=$(TMPDIR)/liba-targ.rlib --target $(TARGET) else -# FreeBSD & OpenBSD support only x86_64 architecture for now +# FreeBSD, OpenBSD, and Bitrig support only x86_64 architecture for now all: endif diff --git a/src/test/run-pass/issue-15149.rs b/src/test/run-pass-fulldeps/issue-15149.rs similarity index 85% rename from src/test/run-pass/issue-15149.rs rename to src/test/run-pass-fulldeps/issue-15149.rs index ee348d9cb0..7e64bbdf70 100644 --- a/src/test/run-pass/issue-15149.rs +++ b/src/test/run-pass-fulldeps/issue-15149.rs @@ -9,16 +9,17 @@ // except according to those terms. // no-prefer-dynamic +// ignore-android -// pretty-expanded FIXME #23616 +#![feature(rustc_private)] -#![feature(fs, process, env, path, rand)] +extern crate rustc_back; use std::env; use std::fs; use std::process; -use std::rand::random; use std::str; +use rustc_back::tempdir::TempDir; fn main() { // If we're the child, make sure we were invoked correctly @@ -28,7 +29,8 @@ fn main() { // checking that it ends_with the executable name. This // is needed because of Windows, which has a different behavior. // See #15149 for more info. - return assert!(args[0].ends_with(&format!("mytest{}", env::consts::EXE_SUFFIX))); + return assert!(args[0].ends_with(&format!("mytest{}", + env::consts::EXE_SUFFIX))); } test(); @@ -39,9 +41,8 @@ fn test() { let my_path = env::current_exe().unwrap(); let my_dir = my_path.parent().unwrap(); - let random_u32: u32 = random(); - let child_dir = my_dir.join(&format!("issue-15149-child-{}", random_u32)); - fs::create_dir(&child_dir).unwrap(); + let child_dir = TempDir::new_in(&my_dir, "issue-15140-child").unwrap(); + let child_dir = child_dir.path(); let child_path = child_dir.join(&format!("mytest{}", env::consts::EXE_SUFFIX)); diff --git a/src/test/run-pass-fulldeps/llvm-pass-plugin.rs b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs new file mode 100644 index 0000000000..5dfef636f9 --- /dev/null +++ b/src/test/run-pass-fulldeps/llvm-pass-plugin.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:llvm_pass_plugin.rs +// ignore-stage1 + +#![feature(plugin)] +#![plugin(llvm_pass_plugin)] + +pub fn main() { } diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index f6ae71f8b6..99e0333ee2 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -17,6 +17,7 @@ extern crate syntax; use syntax::ext::base::ExtCtxt; use syntax::ptr::P; +use syntax::parse::PResult; fn syntax_extension(cx: &ExtCtxt) { let e_toks : Vec = quote_tokens!(cx, 1 + 2); diff --git a/src/test/run-pass-fulldeps/rename-directory.rs b/src/test/run-pass-fulldeps/rename-directory.rs index a1e016bf2e..a0644e513a 100644 --- a/src/test/run-pass-fulldeps/rename-directory.rs +++ b/src/test/run-pass-fulldeps/rename-directory.rs @@ -12,7 +12,6 @@ // because it needs TempDir, which is in extra // ignore-android -// pretty-expanded FIXME #23616 #![feature(rustc_private, path_ext)] diff --git a/src/test/run-pass-valgrind/cleanup-stdin.rs b/src/test/run-pass-valgrind/cleanup-stdin.rs index 301c4b9178..dcdce50c1e 100644 --- a/src/test/run-pass-valgrind/cleanup-stdin.rs +++ b/src/test/run-pass-valgrind/cleanup-stdin.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(old_io, io)] - fn main() { - let _ = std::old_io::stdin(); let _ = std::io::stdin(); + let _ = std::io::stdout(); + let _ = std::io::stderr(); } diff --git a/src/test/run-pass/argument-passing.rs b/src/test/run-pass/argument-passing.rs index 7101cfb557..d2a595804a 100644 --- a/src/test/run-pass/argument-passing.rs +++ b/src/test/run-pass/argument-passing.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct X { x: isize diff --git a/src/test/run-pass/arith-2.rs b/src/test/run-pass/arith-2.rs index 0f4523c681..c93049b87a 100644 --- a/src/test/run-pass/arith-2.rs +++ b/src/test/run-pass/arith-2.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let i32_c: isize = 0x10101010; diff --git a/src/test/run-pass/arith-unsigned.rs b/src/test/run-pass/arith-unsigned.rs index 8a0fc8adc1..e5ff97e3cd 100644 --- a/src/test/run-pass/arith-unsigned.rs +++ b/src/test/run-pass/arith-unsigned.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(type_limits)] diff --git a/src/test/run-pass/artificial-block.rs b/src/test/run-pass/artificial-block.rs index 3348a6754e..53eec3c28c 100644 --- a/src/test/run-pass/artificial-block.rs +++ b/src/test/run-pass/artificial-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> isize { { return 3; } } diff --git a/src/test/run-pass/as-precedence.rs b/src/test/run-pass/as-precedence.rs index 8e38128975..d89607077d 100644 --- a/src/test/run-pass/as-precedence.rs +++ b/src/test/run-pass/as-precedence.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { assert_eq!(3 as usize * 3, 9); diff --git a/src/test/run-pass/asm-in-out-operand.rs b/src/test/run-pass/asm-in-out-operand.rs index 32924bcf74..3eebc7acb0 100644 --- a/src/test/run-pass/asm-in-out-operand.rs +++ b/src/test/run-pass/asm-in-out-operand.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/asm-out-assign.rs b/src/test/run-pass/asm-out-assign.rs index 3cb7f6400d..d7913b473f 100644 --- a/src/test/run-pass/asm-out-assign.rs +++ b/src/test/run-pass/asm-out-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/assign-assign.rs b/src/test/run-pass/assign-assign.rs index 110f4720ce..186f91da07 100644 --- a/src/test/run-pass/assign-assign.rs +++ b/src/test/run-pass/assign-assign.rs @@ -9,7 +9,6 @@ // except according to those terms. // Issue 483 - Assignment expressions result in nil -// pretty-expanded FIXME #23616 fn test_assign() { let mut x: isize; diff --git a/src/test/run-pass/assignability-trait.rs b/src/test/run-pass/assignability-trait.rs index 473f744a3f..f05a1520b8 100644 --- a/src/test/run-pass/assignability-trait.rs +++ b/src/test/run-pass/assignability-trait.rs @@ -12,7 +12,6 @@ // making method calls, but only if there aren't any matches without // it. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/associated-types-basic.rs b/src/test/run-pass/associated-types-basic.rs index d4ed2ee2d6..2617a05fe2 100644 --- a/src/test/run-pass/associated-types-basic.rs +++ b/src/test/run-pass/associated-types-basic.rs @@ -8,13 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(core)] - -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait { +trait Foo { type T; } diff --git a/src/test/run-pass/associated-types-binding-in-trait.rs b/src/test/run-pass/associated-types-binding-in-trait.rs index 39fc224148..d82ba6add7 100644 --- a/src/test/run-pass/associated-types-binding-in-trait.rs +++ b/src/test/run-pass/associated-types-binding-in-trait.rs @@ -11,7 +11,6 @@ // Test a case where the associated type binding (to `bool`, in this // case) is derived from the trait definition. Issue #21636. -// pretty-expanded FIXME #23616 use std::vec; diff --git a/src/test/run-pass/associated-types-bound.rs b/src/test/run-pass/associated-types-bound.rs index 2301821f66..4eacd120bc 100644 --- a/src/test/run-pass/associated-types-bound.rs +++ b/src/test/run-pass/associated-types-bound.rs @@ -10,7 +10,6 @@ // Test equality constrai32s on associated types in a where clause. -// pretty-expanded FIXME #23616 pub trait ToI32 { fn to_i32(&self) -> i32; diff --git a/src/test/run-pass/associated-types-constant-type.rs b/src/test/run-pass/associated-types-constant-type.rs index 5729fab475..77ab616ca9 100644 --- a/src/test/run-pass/associated-types-constant-type.rs +++ b/src/test/run-pass/associated-types-constant-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait SignedUnsigned { type Opposite; diff --git a/src/test/run-pass/associated-types-doubleendediterator-object.rs b/src/test/run-pass/associated-types-doubleendediterator-object.rs index 5dc289194f..1661812520 100644 --- a/src/test/run-pass/associated-types-doubleendediterator-object.rs +++ b/src/test/run-pass/associated-types-doubleendediterator-object.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/associated-types-enum-field-named.rs b/src/test/run-pass/associated-types-enum-field-named.rs index 8cf97fe62f..7014cc59b7 100644 --- a/src/test/run-pass/associated-types-enum-field-named.rs +++ b/src/test/run-pass/associated-types-enum-field-named.rs @@ -10,7 +10,6 @@ // Test associated types appearing in struct-like enum variants. -// pretty-expanded FIXME #23616 use self::VarValue::*; diff --git a/src/test/run-pass/associated-types-enum-field-numbered.rs b/src/test/run-pass/associated-types-enum-field-numbered.rs index 3c57da6b4a..c983fdefc0 100644 --- a/src/test/run-pass/associated-types-enum-field-numbered.rs +++ b/src/test/run-pass/associated-types-enum-field-numbered.rs @@ -10,7 +10,6 @@ // Test associated types appearing in tuple-like enum variants. -// pretty-expanded FIXME #23616 use self::VarValue::*; diff --git a/src/test/run-pass/associated-types-in-default-method.rs b/src/test/run-pass/associated-types-in-default-method.rs index 2a1b9bdd2f..74199f57fb 100644 --- a/src/test/run-pass/associated-types-in-default-method.rs +++ b/src/test/run-pass/associated-types-in-default-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-fn.rs b/src/test/run-pass/associated-types-in-fn.rs index 40b10fbfca..dcd7895fa9 100644 --- a/src/test/run-pass/associated-types-in-fn.rs +++ b/src/test/run-pass/associated-types-in-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-impl-generics.rs b/src/test/run-pass/associated-types-in-impl-generics.rs index 99a9b7c23f..5b81ac7090 100644 --- a/src/test/run-pass/associated-types-in-impl-generics.rs +++ b/src/test/run-pass/associated-types-in-impl-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-in-inherent-method.rs b/src/test/run-pass/associated-types-in-inherent-method.rs index 0012d9d759..5eaf4c2bc8 100644 --- a/src/test/run-pass/associated-types-in-inherent-method.rs +++ b/src/test/run-pass/associated-types-in-inherent-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-issue-20220.rs b/src/test/run-pass/associated-types-issue-20220.rs index 718ea54279..31336787e4 100644 --- a/src/test/run-pass/associated-types-issue-20220.rs +++ b/src/test/run-pass/associated-types-issue-20220.rs @@ -10,7 +10,6 @@ // Test references to `Self::Item` in the trait. Issue #20220. -// pretty-expanded FIXME #23616 use std::vec; diff --git a/src/test/run-pass/associated-types-issue-20371.rs b/src/test/run-pass/associated-types-issue-20371.rs index a601dc0739..c93a0b76a9 100644 --- a/src/test/run-pass/associated-types-issue-20371.rs +++ b/src/test/run-pass/associated-types-issue-20371.rs @@ -13,10 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::marker::MarkerTrait; - impl X for f64 { type Y = isize; } -trait X : MarkerTrait { type Y; } +trait X { type Y; } fn main() {} diff --git a/src/test/run-pass/associated-types-issue-21212.rs b/src/test/run-pass/associated-types-issue-21212.rs index 057677a008..cf4b827211 100644 --- a/src/test/run-pass/associated-types-issue-21212.rs +++ b/src/test/run-pass/associated-types-issue-21212.rs @@ -13,7 +13,6 @@ // where clauses in the environment which in turn required normalizing // `Self::Input`. -// pretty-expanded FIXME #23616 pub trait Parser { type Input; diff --git a/src/test/run-pass/associated-types-iterator-binding.rs b/src/test/run-pass/associated-types-iterator-binding.rs index 24c5a3e9a8..181ce52eb4 100644 --- a/src/test/run-pass/associated-types-iterator-binding.rs +++ b/src/test/run-pass/associated-types-iterator-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn pairwise_sub>(mut t: T) -> isize { let mut result = 0; diff --git a/src/test/run-pass/associated-types-nested-projections.rs b/src/test/run-pass/associated-types-nested-projections.rs index a26b428a4e..83f0d360e6 100644 --- a/src/test/run-pass/associated-types-nested-projections.rs +++ b/src/test/run-pass/associated-types-nested-projections.rs @@ -14,10 +14,9 @@ #![feature(core)] -use std::marker::MarkerTrait; use std::slice; -trait Bound : MarkerTrait {} +trait Bound {} impl<'a> Bound for &'a i32 {} diff --git a/src/test/run-pass/associated-types-normalize-in-bounds-binding.rs b/src/test/run-pass/associated-types-normalize-in-bounds-binding.rs index d95ad2e883..7e2d1aa231 100644 --- a/src/test/run-pass/associated-types-normalize-in-bounds-binding.rs +++ b/src/test/run-pass/associated-types-normalize-in-bounds-binding.rs @@ -13,12 +13,9 @@ // pretty-expanded FIXME #23616 -#![feature(core)] #![allow(dead_code)] -use std::marker::MarkerTrait; - -pub trait Integral : MarkerTrait { +pub trait Integral { type Opposite; } diff --git a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs index 151a9da948..1830b41d0b 100644 --- a/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs +++ b/src/test/run-pass/associated-types-project-from-type-param-via-bound-in-where-clause.rs @@ -12,18 +12,14 @@ // `Item` originates in a where-clause, not the declaration of // `T`. Issue #20300. -// pretty-expanded FIXME #23616 - -#![feature(core)] - -use std::marker::{MarkerTrait, PhantomData}; +use std::marker::{PhantomData}; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; use std::sync::atomic::Ordering::SeqCst; static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; // Preamble. -trait Trait : MarkerTrait { type Item; } +trait Trait { type Item; } struct Struct; impl Trait for Struct { type Item = u32; diff --git a/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs b/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs index 2518ccf1cb..8054b3aa52 100644 --- a/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs +++ b/src/test/run-pass/associated-types-projection-from-known-type-in-impl.rs @@ -10,7 +10,6 @@ // Test where the impl self type uses a projection from a constant type. -// pretty-expanded FIXME #23616 trait Int { diff --git a/src/test/run-pass/associated-types-projection-in-supertrait.rs b/src/test/run-pass/associated-types-projection-in-supertrait.rs index dbc2164c93..70c7602ffc 100644 --- a/src/test/run-pass/associated-types-projection-in-supertrait.rs +++ b/src/test/run-pass/associated-types-projection-in-supertrait.rs @@ -11,7 +11,6 @@ // Test that we are handle to correctly handle a projection type // that appears in a supertrait bound. Issue #20559. -// pretty-expanded FIXME #23616 trait A { diff --git a/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs b/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs new file mode 100644 index 0000000000..6070cff9a2 --- /dev/null +++ b/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs @@ -0,0 +1,43 @@ +// 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. + +// Check that we do not get an error when you use `::Value` in +// the trait definition if there is no default method and for every impl, +// `Self` does implement `Get`. +// +// See also compile-fail tests associated-types-no-suitable-supertrait +// and associated-types-no-suitable-supertrait-2, which show how small +// variants of the code below can fail. + +trait Get { + type Value; +} + +trait Other { + fn okay(&self, foo: U, bar: ::Value); +} + +impl Get for () { + type Value = f32; +} + +impl Get for f64 { + type Value = u32; +} + +impl Other for () { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +impl Other for f64 { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +fn main() { } diff --git a/src/test/run-pass/associated-types-ref-in-struct-literal.rs b/src/test/run-pass/associated-types-ref-in-struct-literal.rs index 945340008d..3b7fb65a8b 100644 --- a/src/test/run-pass/associated-types-ref-in-struct-literal.rs +++ b/src/test/run-pass/associated-types-ref-in-struct-literal.rs @@ -10,7 +10,6 @@ // Test associated type references in a struct literal. Issue #20535. -// pretty-expanded FIXME #23616 pub trait Foo { type Bar; diff --git a/src/test/run-pass/associated-types-return.rs b/src/test/run-pass/associated-types-return.rs index f190e81d8a..5bba54e57b 100644 --- a/src/test/run-pass/associated-types-return.rs +++ b/src/test/run-pass/associated-types-return.rs @@ -10,7 +10,6 @@ // Test equality constraints on associated types in a where clause. -// pretty-expanded FIXME #23616 pub trait Foo { type A; diff --git a/src/test/run-pass/associated-types-simple.rs b/src/test/run-pass/associated-types-simple.rs index 5a2761365b..776b2183d3 100644 --- a/src/test/run-pass/associated-types-simple.rs +++ b/src/test/run-pass/associated-types-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Get { type Value; diff --git a/src/test/run-pass/associated-types-stream.rs b/src/test/run-pass/associated-types-stream.rs index a2b7cf2106..6adfaabcc2 100644 --- a/src/test/run-pass/associated-types-stream.rs +++ b/src/test/run-pass/associated-types-stream.rs @@ -11,7 +11,6 @@ // Test references to the trait `Stream` in the bounds for associated // types defined on `Stream`. Issue #20551. -// pretty-expanded FIXME #23616 trait Stream { type Car; diff --git a/src/test/run-pass/associated-types-struct-field-named.rs b/src/test/run-pass/associated-types-struct-field-named.rs index d1872e4fb5..00746c32e1 100644 --- a/src/test/run-pass/associated-types-struct-field-named.rs +++ b/src/test/run-pass/associated-types-struct-field-named.rs @@ -11,7 +11,6 @@ // Test that we correctly normalize the type of a struct field // which has an associated type. -// pretty-expanded FIXME #23616 pub trait UnifyKey { type Value; diff --git a/src/test/run-pass/associated-types-struct-field-numbered.rs b/src/test/run-pass/associated-types-struct-field-numbered.rs index 3d97c503dc..25e89892a2 100644 --- a/src/test/run-pass/associated-types-struct-field-numbered.rs +++ b/src/test/run-pass/associated-types-struct-field-numbered.rs @@ -11,7 +11,6 @@ // Test that we correctly normalize the type of a struct field // which has an associated type. -// pretty-expanded FIXME #23616 pub trait UnifyKey { type Value; diff --git a/src/test/run-pass/associated-types-sugar-path.rs b/src/test/run-pass/associated-types-sugar-path.rs index 353b49b49c..1432369f71 100644 --- a/src/test/run-pass/associated-types-sugar-path.rs +++ b/src/test/run-pass/associated-types-sugar-path.rs @@ -10,7 +10,6 @@ // Test paths to associated types using the type-parameter-only sugar. -// pretty-expanded FIXME #23616 pub trait Foo { type A; diff --git a/src/test/run-pass/atomic-print.rs b/src/test/run-pass/atomic-print.rs new file mode 100644 index 0000000000..ae0a358ac4 --- /dev/null +++ b/src/test/run-pass/atomic-print.rs @@ -0,0 +1,48 @@ +// 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 std::{env, fmt, process, sync, thread}; + +struct SlowFmt(u32); +impl fmt::Debug for SlowFmt { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + thread::sleep_ms(3); + self.0.fmt(f) + } +} + +fn do_print(x: u32) { + let x = SlowFmt(x); + println!("{:?}{:?}{:?}{:?}{:?}", x, x, x, x, x); +} + +fn main(){ + if env::args().count() == 2 { + let barrier = sync::Arc::new(sync::Barrier::new(2)); + let tbarrier = barrier.clone(); + let t = thread::spawn(move || { + tbarrier.wait(); + do_print(1); + }); + barrier.wait(); + do_print(2); + t.join(); + } else { + let this = env::args().next().unwrap(); + let output = process::Command::new(this).arg("-").output().unwrap(); + for line in String::from_utf8(output.stdout).unwrap().lines() { + match line.chars().next().unwrap() { + '1' => assert_eq!(line, "11111"), + '2' => assert_eq!(line, "22222"), + _ => panic!("Unexpected character") + } + } + } +} diff --git a/src/test/run-pass/attr-main-2.rs b/src/test/run-pass/attr-main-2.rs index 4680f47fad..b3c9ea541b 100644 --- a/src/test/run-pass/attr-main-2.rs +++ b/src/test/run-pass/attr-main-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(main)] diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs index af8e4b7d4a..893fb85b52 100644 --- a/src/test/run-pass/attr-no-drop-flag-size.rs +++ b/src/test/run-pass/attr-no-drop-flag-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/auto-loop.rs b/src/test/run-pass/auto-loop.rs index 2e79183755..babc0db4c3 100644 --- a/src/test/run-pass/auto-loop.rs +++ b/src/test/run-pass/auto-loop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut sum = 0; diff --git a/src/test/run-pass/auto-ref-sliceable.rs b/src/test/run-pass/auto-ref-sliceable.rs index 6dab0e5197..5b12edb427 100644 --- a/src/test/run-pass/auto-ref-sliceable.rs +++ b/src/test/run-pass/auto-ref-sliceable.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait Pushable { fn push_val(&mut self, t: T); diff --git a/src/test/run-pass/autobind.rs b/src/test/run-pass/autobind.rs index 7d30b549eb..1f3d17ad55 100644 --- a/src/test/run-pass/autobind.rs +++ b/src/test/run-pass/autobind.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: Vec) -> T { return x.into_iter().next().unwrap(); } diff --git a/src/test/run-pass/autoderef-method-on-trait.rs b/src/test/run-pass/autoderef-method-on-trait.rs index d7eee85f50..40acb6eb9f 100644 --- a/src/test/run-pass/autoderef-method-on-trait.rs +++ b/src/test/run-pass/autoderef-method-on-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] @@ -22,6 +21,6 @@ impl double for usize { } pub fn main() { - let x: Box<_> = box() (box 3us as Box); + let x: Box<_> = box() (box 3usize as Box); assert_eq!(x.double(), 6); } diff --git a/src/test/run-pass/autoderef-method-priority.rs b/src/test/run-pass/autoderef-method-priority.rs index 6c52035b70..c80a92a185 100644 --- a/src/test/run-pass/autoderef-method-priority.rs +++ b/src/test/run-pass/autoderef-method-priority.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs index 809ab0a352..2a782cfa17 100644 --- a/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs +++ b/src/test/run-pass/autoderef-method-twice-but-not-thrice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method-twice.rs b/src/test/run-pass/autoderef-method-twice.rs index 9c7828c893..a1bcf65ab7 100644 --- a/src/test/run-pass/autoderef-method-twice.rs +++ b/src/test/run-pass/autoderef-method-twice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoderef-method.rs b/src/test/run-pass/autoderef-method.rs index e63dd07eb0..326218674a 100644 --- a/src/test/run-pass/autoderef-method.rs +++ b/src/test/run-pass/autoderef-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/autoref-intermediate-types-issue-3585.rs b/src/test/run-pass/autoref-intermediate-types-issue-3585.rs index 0f935776fc..05f12fd089 100644 --- a/src/test/run-pass/autoref-intermediate-types-issue-3585.rs +++ b/src/test/run-pass/autoref-intermediate-types-issue-3585.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 14d8bce061..f4b62eb2e7 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -11,11 +11,8 @@ // no-pretty-expanded FIXME #15189 // ignore-windows FIXME #13259 -#![feature(unboxed_closures)] -#![feature(unsafe_destructor, old_io, collections)] - use std::env; -use std::old_io::process::Command; +use std::process::{Command, Stdio}; use std::str; use std::ops::{Drop, FnMut, FnOnce}; @@ -40,44 +37,49 @@ fn double() { panic!("once"); } -fn runtest(me: &str) { - let mut template = Command::new(me); - template.env("IS_TEST", "1"); +fn template(me: &str) -> Command { + let mut m = Command::new(me); + m.env("IS_TEST", "1") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + return m; +} +fn runtest(me: &str) { // Make sure that the stack trace is printed - let p = template.clone().arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); + let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); assert!(s.contains("stack backtrace") && s.contains("foo::h"), "bad output: {}", s); // Make sure the stack trace is *not* printed // (Remove RUST_BACKTRACE from our own environment, in case developer // is running `make check` with it on.) - let p = template.clone().arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap(); + let p = template(me).arg("fail").env_remove("RUST_BACKTRACE").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); assert!(!s.contains("stack backtrace") && !s.contains("foo::h"), "bad output2: {}", s); // Make sure a stack trace is printed - let p = template.clone().arg("double-fail").spawn().unwrap(); + let p = template(me).arg("double-fail").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); // loosened the following from double::h to double:: due to // spurious failures on mac, 32bit, optimized assert!(s.contains("stack backtrace") && s.contains("double::"), "bad output3: {}", s); // Make sure a stack trace isn't printed too many times - let p = template.clone().arg("double-fail") + let p = template(me).arg("double-fail") .env("RUST_BACKTRACE", "1").spawn().unwrap(); let out = p.wait_with_output().unwrap(); assert!(!out.status.success()); - let s = str::from_utf8(&out.error).unwrap(); + let s = str::from_utf8(&out.stderr).unwrap(); let mut i = 0; for _ in 0..2 { i += s[i + 10..].find("stack backtrace").unwrap() + 10; diff --git a/src/test/run-pass/big-literals.rs b/src/test/run-pass/big-literals.rs index ab9d892ce2..19c0e7baaa 100644 --- a/src/test/run-pass/big-literals.rs +++ b/src/test/run-pass/big-literals.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/binary-minus-without-space.rs b/src/test/run-pass/binary-minus-without-space.rs index 1fe9dde844..01a9ec8093 100644 --- a/src/test/run-pass/binary-minus-without-space.rs +++ b/src/test/run-pass/binary-minus-without-space.rs @@ -10,7 +10,6 @@ // Check that issue #954 stays fixed -// pretty-expanded FIXME #23616 pub fn main() { match -1 { -1 => {}, _ => panic!("wat") } diff --git a/src/test/run-pass/bind-by-move.rs b/src/test/run-pass/bind-by-move.rs index 5a6e801501..9be7d63ab9 100644 --- a/src/test/run-pass/bind-by-move.rs +++ b/src/test/run-pass/bind-by-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Arc; fn dispose(_x: Arc) { } diff --git a/src/test/run-pass/bind-field-short-with-modifiers.rs b/src/test/run-pass/bind-field-short-with-modifiers.rs index e61ff61a21..b4c38bf450 100644 --- a/src/test/run-pass/bind-field-short-with-modifiers.rs +++ b/src/test/run-pass/bind-field-short-with-modifiers.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { struct Foo { x: isize, y: isize } diff --git a/src/test/run-pass/block-arg-call-as.rs b/src/test/run-pass/block-arg-call-as.rs index 5944438e20..73cba2e4e0 100644 --- a/src/test/run-pass/block-arg-call-as.rs +++ b/src/test/run-pass/block-arg-call-as.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn asBlock(f: F) -> usize where F: FnOnce() -> usize { return f(); diff --git a/src/test/run-pass/block-expr-precedence.rs b/src/test/run-pass/block-expr-precedence.rs index 01bd8ce10c..ac8f501257 100644 --- a/src/test/run-pass/block-expr-precedence.rs +++ b/src/test/run-pass/block-expr-precedence.rs @@ -13,7 +13,6 @@ // no-reformat -// pretty-expanded FIXME #23616 /* * diff --git a/src/test/run-pass/block-fn-coerce.rs b/src/test/run-pass/block-fn-coerce.rs index 0addd33c1e..3e6109da39 100644 --- a/src/test/run-pass/block-fn-coerce.rs +++ b/src/test/run-pass/block-fn-coerce.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn force(f: F) -> isize where F: FnOnce() -> isize { return f(); } diff --git a/src/test/run-pass/bool-not.rs b/src/test/run-pass/bool-not.rs index c46684af6e..fa0b86d0a0 100644 --- a/src/test/run-pass/bool-not.rs +++ b/src/test/run-pass/bool-not.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { if !false { assert!((true)); } else { assert!((false)); } diff --git a/src/test/run-pass/bool.rs b/src/test/run-pass/bool.rs index a2b19d3205..53b568b06b 100644 --- a/src/test/run-pass/bool.rs +++ b/src/test/run-pass/bool.rs @@ -10,7 +10,6 @@ // Basic boolean tests -// pretty-expanded FIXME #23616 use std::cmp::Ordering::{Equal, Greater, Less}; use std::ops::{BitAnd, BitOr, BitXor}; diff --git a/src/test/run-pass/borrow-tuple-fields.rs b/src/test/run-pass/borrow-tuple-fields.rs index 7cf61bd569..f0d0968819 100644 --- a/src/test/run-pass/borrow-tuple-fields.rs +++ b/src/test/run-pass/borrow-tuple-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo(isize, isize); diff --git a/src/test/run-pass/borrowck-borrow-from-expr-block.rs b/src/test/run-pass/borrowck-borrow-from-expr-block.rs index 24c7285b1f..7fdc65a96e 100644 --- a/src/test/run-pass/borrowck-borrow-from-expr-block.rs +++ b/src/test/run-pass/borrowck-borrow-from-expr-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-closures-two-imm.rs b/src/test/run-pass/borrowck-closures-two-imm.rs index 6ccb2203bc..5b15c8f079 100644 --- a/src/test/run-pass/borrowck-closures-two-imm.rs +++ b/src/test/run-pass/borrowck-closures-two-imm.rs @@ -14,7 +14,6 @@ // that the main function can read the variable too while // the closures are in scope. Issue #6801. -// pretty-expanded FIXME #23616 fn a() -> i32 { let mut x = 3; diff --git a/src/test/run-pass/borrowck-fixed-length-vecs.rs b/src/test/run-pass/borrowck-fixed-length-vecs.rs index 3f38a8df04..0e33351894 100644 --- a/src/test/run-pass/borrowck-fixed-length-vecs.rs +++ b/src/test/run-pass/borrowck-fixed-length-vecs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [22]; diff --git a/src/test/run-pass/borrowck-freeze-frozen-mut.rs b/src/test/run-pass/borrowck-freeze-frozen-mut.rs index eaa78553d8..380bd398a7 100644 --- a/src/test/run-pass/borrowck-freeze-frozen-mut.rs +++ b/src/test/run-pass/borrowck-freeze-frozen-mut.rs @@ -10,7 +10,6 @@ // Test that a `&mut` inside of an `&` is freezable. -// pretty-expanded FIXME #23616 struct MutSlice<'a, T:'a> { data: &'a mut [T] diff --git a/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs b/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs index b40504f37d..fb30c85e70 100644 --- a/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs +++ b/src/test/run-pass/borrowck-macro-interaction-issue-6304.rs @@ -11,7 +11,6 @@ // Check that we do not ICE when compiling this // macro, which reuses the expression `$id` -// pretty-expanded FIXME #23616 #![feature(box_patterns)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-move-by-capture-ok.rs b/src/test/run-pass/borrowck-move-by-capture-ok.rs index 7c03c6a9a4..bbc668f5ca 100644 --- a/src/test/run-pass/borrowck-move-by-capture-ok.rs +++ b/src/test/run-pass/borrowck-move-by-capture-ok.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs index 4d37bcb5a4..d55517c65d 100644 --- a/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs +++ b/src/test/run-pass/borrowck-mut-vec-as-imm-slice.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn want_slice(v: &[isize]) -> isize { let mut sum = 0; diff --git a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs index c3b69333dc..e0a5db678d 100644 --- a/src/test/run-pass/borrowck-pat-reassign-no-binding.rs +++ b/src/test/run-pass/borrowck-pat-reassign-no-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut x = None; diff --git a/src/test/run-pass/borrowck-rvalues-mutable.rs b/src/test/run-pass/borrowck-rvalues-mutable.rs index 1b20f6c706..045e8d952a 100644 --- a/src/test/run-pass/borrowck-rvalues-mutable.rs +++ b/src/test/run-pass/borrowck-rvalues-mutable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Counter { value: usize diff --git a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs index 36a84a62d4..59a5fea769 100644 --- a/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs +++ b/src/test/run-pass/borrowck-scope-of-deref-issue-4666.rs @@ -12,7 +12,6 @@ // limited to the deref operation itself, and does not infect the // block as a whole. -// pretty-expanded FIXME #23616 struct Box { x: usize diff --git a/src/test/run-pass/borrowck-univariant-enum.rs b/src/test/run-pass/borrowck-univariant-enum.rs index a5c68c5ecf..2e8ddb0806 100644 --- a/src/test/run-pass/borrowck-univariant-enum.rs +++ b/src/test/run-pass/borrowck-univariant-enum.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/borrowed-ptr-pattern-2.rs b/src/test/run-pass/borrowed-ptr-pattern-2.rs index aaf962577f..3e47764ba0 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-2.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(s: &String) -> bool { match &**s { diff --git a/src/test/run-pass/borrowed-ptr-pattern-3.rs b/src/test/run-pass/borrowed-ptr-pattern-3.rs index c8cc29b9bd..91228efb9c 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-3.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-3.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo<'r>(s: &'r usize) -> bool { match s { diff --git a/src/test/run-pass/borrowed-ptr-pattern-infallible.rs b/src/test/run-pass/borrowed-ptr-pattern-infallible.rs index 69cb27dcf8..6656eb41f2 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-infallible.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-infallible.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let (&x, &y) = (&3, &'a'); diff --git a/src/test/run-pass/borrowed-ptr-pattern-option.rs b/src/test/run-pass/borrowed-ptr-pattern-option.rs index 14b6c32a11..e1e9381eeb 100644 --- a/src/test/run-pass/borrowed-ptr-pattern-option.rs +++ b/src/test/run-pass/borrowed-ptr-pattern-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn select<'r>(x: &'r Option, y: &'r Option) -> &'r Option { match (x, y) { diff --git a/src/test/run-pass/borrowed-ptr-pattern.rs b/src/test/run-pass/borrowed-ptr-pattern.rs index 52322c4123..3042ff7743 100644 --- a/src/test/run-pass/borrowed-ptr-pattern.rs +++ b/src/test/run-pass/borrowed-ptr-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &T) -> T{ match x { diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index 80934c4851..ea136e2dc4 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut i = 0; diff --git a/src/test/run-pass/bug-7183-generics.rs b/src/test/run-pass/bug-7183-generics.rs index 5467ed10e9..80fd09114f 100644 --- a/src/test/run-pass/bug-7183-generics.rs +++ b/src/test/run-pass/bug-7183-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Speak : Sized { fn say(&self, s:&str) -> String; diff --git a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs index eb6d102833..c5064d56ca 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-transitive.rs @@ -14,7 +14,6 @@ // a Send. Basically this just makes sure rustc is using // each_bound_trait_and_supertraits in type_contents correctly. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{channel, Sender}; diff --git a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs index 082f5944fd..183e6fe232 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities-xc.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities-xc.rs @@ -14,7 +14,6 @@ // Tests "capabilities" granted by traits with super-builtin-kinds, // even when using them cross-crate. -// pretty-expanded FIXME #23616 extern crate trait_superkinds_in_metadata; diff --git a/src/test/run-pass/builtin-superkinds-capabilities.rs b/src/test/run-pass/builtin-superkinds-capabilities.rs index 594fb5ec70..a4d5c943b1 100644 --- a/src/test/run-pass/builtin-superkinds-capabilities.rs +++ b/src/test/run-pass/builtin-superkinds-capabilities.rs @@ -12,7 +12,6 @@ // builtin-kinds, e.g., if a trait requires Send to implement, then // at usage site of that trait, we know we have the Send capability. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{channel, Sender, Receiver}; diff --git a/src/test/run-pass/builtin-superkinds-self-type.rs b/src/test/run-pass/builtin-superkinds-self-type.rs index 924a8c023f..c4dc7d78b0 100644 --- a/src/test/run-pass/builtin-superkinds-self-type.rs +++ b/src/test/run-pass/builtin-superkinds-self-type.rs @@ -11,7 +11,6 @@ // Tests the ability for the Self type in default methods to use // capabilities granted by builtin kinds as supertraits. -// pretty-expanded FIXME #23616 use std::sync::mpsc::{Sender, channel}; diff --git a/src/test/run-pass/by-value-self-in-mut-slot.rs b/src/test/run-pass/by-value-self-in-mut-slot.rs index 464c24fc8b..5bbdec95b1 100644 --- a/src/test/run-pass/by-value-self-in-mut-slot.rs +++ b/src/test/run-pass/by-value-self-in-mut-slot.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct X { a: isize diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index dcf1b55400..d6b35f5385 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc, std_misc)] diff --git a/src/test/run-pass/call-closure-from-overloaded-op.rs b/src/test/run-pass/call-closure-from-overloaded-op.rs index e3ee282ec2..e35398a229 100644 --- a/src/test/run-pass/call-closure-from-overloaded-op.rs +++ b/src/test/run-pass/call-closure-from-overloaded-op.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo() -> isize { 22 } diff --git a/src/test/run-pass/capture-clauses-boxed-closures.rs b/src/test/run-pass/capture-clauses-boxed-closures.rs index 5bf6f5fb04..45cec79e1a 100644 --- a/src/test/run-pass/capture-clauses-boxed-closures.rs +++ b/src/test/run-pass/capture-clauses-boxed-closures.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn each(x: &[T], mut f: F) where F: FnMut(&T) { for val in x { diff --git a/src/test/run-pass/capture-clauses-unboxed-closures.rs b/src/test/run-pass/capture-clauses-unboxed-closures.rs index 448ed76fe9..5e7d5aacb8 100644 --- a/src/test/run-pass/capture-clauses-unboxed-closures.rs +++ b/src/test/run-pass/capture-clauses-unboxed-closures.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/capturing-logging.rs b/src/test/run-pass/capturing-logging.rs deleted file mode 100644 index f9b429a935..0000000000 --- a/src/test/run-pass/capturing-logging.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2014 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. - -// exec-env:RUST_LOG=info - -// pretty-expanded FIXME #23616 - -#![allow(unknown_features)] -#![feature(box_syntax, old_io, rustc_private, std_misc)] - -#[macro_use] -extern crate log; - -use log::{set_logger, Logger, LogRecord}; -use std::sync::mpsc::channel; -use std::fmt; -use std::old_io::{ChanReader, ChanWriter, Reader, Writer}; -use std::thread; - -struct MyWriter(ChanWriter); - -impl Logger for MyWriter { - fn log(&mut self, record: &LogRecord) { - let MyWriter(ref mut inner) = *self; - write!(inner, "{}", record.args); - } -} - -fn main() { - let (tx, rx) = channel(); - let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx)); - let _t = thread::scoped(move|| { - set_logger(box MyWriter(w) as Box); - debug!("debug"); - info!("info"); - }); - let s = r.read_to_string().unwrap(); - assert!(s.contains("info")); - assert!(!s.contains("debug")); -} diff --git a/src/test/run-pass/cast.rs b/src/test/run-pass/cast.rs index 03a73555f8..bb60626a4b 100644 --- a/src/test/run-pass/cast.rs +++ b/src/test/run-pass/cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let i: isize = 'Q' as isize; diff --git a/src/test/run-pass/cci_nested_exe.rs b/src/test/run-pass/cci_nested_exe.rs index 6654698830..e4f4a4f3a5 100644 --- a/src/test/run-pass/cci_nested_exe.rs +++ b/src/test/run-pass/cci_nested_exe.rs @@ -10,7 +10,6 @@ // aux-build:cci_nested_lib.rs -// pretty-expanded FIXME #23616 #![feature(globs)] diff --git a/src/test/run-pass/cell-does-not-clone.rs b/src/test/run-pass/cell-does-not-clone.rs index c87a3e8bb9..c1fcf49654 100644 --- a/src/test/run-pass/cell-does-not-clone.rs +++ b/src/test/run-pass/cell-does-not-clone.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/cfg-macros-foo.rs b/src/test/run-pass/cfg-macros-foo.rs index 5fa1bc47f8..36b9ce1585 100644 --- a/src/test/run-pass/cfg-macros-foo.rs +++ b/src/test/run-pass/cfg-macros-foo.rs @@ -13,7 +13,6 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-notfoo.rs) -// pretty-expanded FIXME #23616 #[cfg(foo)] #[macro_use] diff --git a/src/test/run-pass/cfg-macros-notfoo.rs b/src/test/run-pass/cfg-macros-notfoo.rs index 7cddac1603..4e1b833add 100644 --- a/src/test/run-pass/cfg-macros-notfoo.rs +++ b/src/test/run-pass/cfg-macros-notfoo.rs @@ -13,7 +13,6 @@ // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) -// pretty-expanded FIXME #23616 #[cfg(foo)] #[macro_use] diff --git a/src/test/run-pass/cfgs-on-items.rs b/src/test/run-pass/cfgs-on-items.rs index 5c22d5c869..1b692d8bd5 100644 --- a/src/test/run-pass/cfgs-on-items.rs +++ b/src/test/run-pass/cfgs-on-items.rs @@ -11,7 +11,6 @@ // compile-flags: --cfg fooA --cfg fooB // fooA AND !bar -// pretty-expanded FIXME #23616 #[cfg(all(fooA, not(bar)))] fn foo1() -> isize { 1 } diff --git a/src/test/run-pass/char.rs b/src/test/run-pass/char.rs index 801b01918e..d63512f806 100644 --- a/src/test/run-pass/char.rs +++ b/src/test/run-pass/char.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let c: char = 'x'; diff --git a/src/test/run-pass/check-static-mut-slices.rs b/src/test/run-pass/check-static-mut-slices.rs index 19c3458ef7..5959dd4c38 100644 --- a/src/test/run-pass/check-static-mut-slices.rs +++ b/src/test/run-pass/check-static-mut-slices.rs @@ -10,7 +10,6 @@ // Checks that mutable static items can have mutable slices -// pretty-expanded FIXME #23616 static mut TEST: &'static mut [isize] = &mut [1]; diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs index 8a7ae1de9b..8408597f35 100644 --- a/src/test/run-pass/check-static-slice.rs +++ b/src/test/run-pass/check-static-slice.rs @@ -11,7 +11,6 @@ // Check that the various ways of getting to a reference to a vec (both sized // and unsized) work properly. -// pretty-expanded FIXME #23616 const aa: [isize; 3] = [1, 2, 3]; const ab: &'static [isize; 3] = &aa; diff --git a/src/test/run-pass/class-exports.rs b/src/test/run-pass/class-exports.rs index 675acf1dd6..6783609b25 100644 --- a/src/test/run-pass/class-exports.rs +++ b/src/test/run-pass/class-exports.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /* Test that exporting a class also exports its public fields and methods */ diff --git a/src/test/run-pass/class-method-cross-crate.rs b/src/test/run-pass/class-method-cross-crate.rs index a5c60e3a7b..6ab158dc37 100644 --- a/src/test/run-pass/class-method-cross-crate.rs +++ b/src/test/run-pass/class-method-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_2.rs -// pretty-expanded FIXME #23616 extern crate cci_class_2; use cci_class_2::kitties::cat; diff --git a/src/test/run-pass/class-methods-cross-crate.rs b/src/test/run-pass/class-methods-cross-crate.rs index 73abaf7d34..6665710075 100644 --- a/src/test/run-pass/class-methods-cross-crate.rs +++ b/src/test/run-pass/class-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_3.rs -// pretty-expanded FIXME #23616 extern crate cci_class_3; use cci_class_3::kitties::cat; diff --git a/src/test/run-pass/class-methods.rs b/src/test/run-pass/class-methods.rs index d454bdd73a..93af906bd5 100644 --- a/src/test/run-pass/class-methods.rs +++ b/src/test/run-pass/class-methods.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/class-poly-methods-cross-crate.rs b/src/test/run-pass/class-poly-methods-cross-crate.rs index 6537a931fa..4d247bde19 100644 --- a/src/test/run-pass/class-poly-methods-cross-crate.rs +++ b/src/test/run-pass/class-poly-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_6.rs -// pretty-expanded FIXME #23616 extern crate cci_class_6; use cci_class_6::kitties::cat; diff --git a/src/test/run-pass/class-poly-methods.rs b/src/test/run-pass/class-poly-methods.rs index 27f872d532..2528ff5128 100644 --- a/src/test/run-pass/class-poly-methods.rs +++ b/src/test/run-pass/class-poly-methods.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { info : Vec , diff --git a/src/test/run-pass/classes-cross-crate.rs b/src/test/run-pass/classes-cross-crate.rs index 36d7bd6b3c..3d99aa1ef1 100644 --- a/src/test/run-pass/classes-cross-crate.rs +++ b/src/test/run-pass/classes-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class_4.rs -// pretty-expanded FIXME #23616 extern crate cci_class_4; use cci_class_4::kitties::cat; diff --git a/src/test/run-pass/classes-simple-cross-crate.rs b/src/test/run-pass/classes-simple-cross-crate.rs index cfa13dbe62..db15001c62 100644 --- a/src/test/run-pass/classes-simple-cross-crate.rs +++ b/src/test/run-pass/classes-simple-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:cci_class.rs -// pretty-expanded FIXME #23616 extern crate cci_class; use cci_class::kitties::cat; diff --git a/src/test/run-pass/classes-simple-method.rs b/src/test/run-pass/classes-simple-method.rs index 0d9f859d2d..64ec2ea7e7 100644 --- a/src/test/run-pass/classes-simple-method.rs +++ b/src/test/run-pass/classes-simple-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/classes-simple.rs b/src/test/run-pass/classes-simple.rs index f520623a75..c475fb2cff 100644 --- a/src/test/run-pass/classes-simple.rs +++ b/src/test/run-pass/classes-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs b/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs index 1d0030fd3d..d813a6d810 100644 --- a/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs +++ b/src/test/run-pass/cleanup-rvalue-during-if-and-while.rs @@ -12,7 +12,6 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs index 3b5421e5af..344ea63c7c 100644 --- a/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ b/src/test/run-pass/cleanup-rvalue-temp-during-incomplete-alloc.rs @@ -24,7 +24,6 @@ // It's unclear how likely such a bug is to recur, but it seems like a // scenario worth testing. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/clone-with-exterior.rs b/src/test/run-pass/clone-with-exterior.rs index 16efceb9d7..5a7b1c83df 100644 --- a/src/test/run-pass/clone-with-exterior.rs +++ b/src/test/run-pass/clone-with-exterior.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc)] @@ -23,8 +22,8 @@ struct Pair { pub fn main() { let z: Box<_> = box Pair { a : 10, b : 12}; - let _t = thread::scoped(move|| { + thread::spawn(move|| { assert_eq!(z.a, 10); assert_eq!(z.b, 12); - }); + }).join(); } diff --git a/src/test/run-pass/closure-inference.rs b/src/test/run-pass/closure-inference.rs index 06b6e1b5ab..630a510ca6 100644 --- a/src/test/run-pass/closure-inference.rs +++ b/src/test/run-pass/closure-inference.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(i: isize) -> isize { i + 1 } diff --git a/src/test/run-pass/closure-inference2.rs b/src/test/run-pass/closure-inference2.rs index 328a27b3f1..2f24cd4ce4 100644 --- a/src/test/run-pass/closure-inference2.rs +++ b/src/test/run-pass/closure-inference2.rs @@ -10,7 +10,6 @@ // Test a rather underspecified example: -// pretty-expanded FIXME #23616 pub fn main() { let f = {|i| i}; diff --git a/src/test/run-pass/closure-reform.rs b/src/test/run-pass/closure-reform.rs index fefab45714..50f05c050b 100644 --- a/src/test/run-pass/closure-reform.rs +++ b/src/test/run-pass/closure-reform.rs @@ -14,7 +14,6 @@ #![feature(unboxed_closures, old_io)] use std::mem; -use std::old_io::stdio::println; fn call_it(f: F) where F : FnOnce(String) -> String @@ -62,7 +61,8 @@ pub fn main() { // External functions - call_bare(println); + fn foo(s: &str) {} + call_bare(foo); - call_bare_again(println); + call_bare_again(foo); } diff --git a/src/test/run-pass/cmp-default.rs b/src/test/run-pass/cmp-default.rs index 2b7557c7bc..cd3f556864 100644 --- a/src/test/run-pass/cmp-default.rs +++ b/src/test/run-pass/cmp-default.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cmp::Ordering; diff --git a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs index 6000b358ac..5258ad1af5 100644 --- a/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-ptr-rcvr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct SpeechMaker { speeches: usize diff --git a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs index 2e41ff3a56..4e116ae146 100644 --- a/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-imm-vec-rcvr.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn bar(v: &mut [usize]) -> Vec { v.to_vec() diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs index 803f86e0fb..ce0bc33905 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-arg.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn reverse(v: &mut [usize]) { v.reverse(); diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs index a5fac12735..066b33e007 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn bar(v: &mut [usize]) { v.reverse(); diff --git a/src/test/compile-fail/coherence-subtyping.rs b/src/test/run-pass/coherence-subtyping.rs similarity index 94% rename from src/test/compile-fail/coherence-subtyping.rs rename to src/test/run-pass/coherence-subtyping.rs index 897cb083f8..082a39f563 100644 --- a/src/test/compile-fail/coherence-subtyping.rs +++ b/src/test/run-pass/coherence-subtyping.rs @@ -16,7 +16,6 @@ trait Contravariant { } impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) { - //~^ ERROR E0119 } impl Contravariant for for<'a> fn(&'a u8, &'a u8) { @@ -29,7 +28,6 @@ trait Covariant { } impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) { - //~^ ERROR E0119 } impl Covariant for for<'a> fn(&'a u8, &'a u8) { @@ -38,7 +36,7 @@ impl Covariant for for<'a> fn(&'a u8, &'a u8) { /////////////////////////////////////////////////////////////////////////// trait Invariant { - fn foo(&self) -> Self { } + fn foo(&self) { } } impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) { diff --git a/src/test/run-pass/coherence_copy_like.rs b/src/test/run-pass/coherence_copy_like.rs index db9893613a..71db5225ec 100644 --- a/src/test/run-pass/coherence_copy_like.rs +++ b/src/test/run-pass/coherence_copy_like.rs @@ -15,11 +15,9 @@ extern crate coherence_copy_like_lib as lib; -use std::marker::MarkerTrait; - struct MyType { x: i32 } -trait MyTrait : MarkerTrait { } +trait MyTrait { } impl MyTrait for T { } impl MyTrait for MyType { } impl<'a> MyTrait for &'a MyType { } diff --git a/src/test/run-pass/comm.rs b/src/test/run-pass/comm.rs index 859599596a..72f623ccfd 100644 --- a/src/test/run-pass/comm.rs +++ b/src/test/run-pass/comm.rs @@ -15,11 +15,12 @@ use std::sync::mpsc::{channel, Sender}; pub fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { child(&tx) }); + let t = thread::spawn(move|| { child(&tx) }); let y = rx.recv().unwrap(); println!("received"); println!("{}", y); assert_eq!(y, 10); + t.join(); } fn child(c: &Sender) { diff --git a/src/test/run-pass/compare-generic-enums.rs b/src/test/run-pass/compare-generic-enums.rs index 6994558487..228a73326e 100644 --- a/src/test/run-pass/compare-generic-enums.rs +++ b/src/test/run-pass/compare-generic-enums.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type an_int = isize; diff --git a/src/test/run-pass/concat.rs b/src/test/run-pass/concat.rs index 7441d1f21b..9a2390a9e6 100644 --- a/src/test/run-pass/concat.rs +++ b/src/test/run-pass/concat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(format!(concat!("foo", "bar", "{}"), "baz"), "foobarbaz".to_string()); diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index e6660bb9ae..5891d9f1aa 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -9,7 +9,6 @@ // except according to those terms. // Crate use statements -// pretty-expanded FIXME #23616 #[cfg(bogus)] use flippity; diff --git a/src/test/run-pass/conditional-debug-macro-off.rs b/src/test/run-pass/conditional-debug-macro-off.rs index 192e647f5c..c6beb5ba35 100644 --- a/src/test/run-pass/conditional-debug-macro-off.rs +++ b/src/test/run-pass/conditional-debug-macro-off.rs @@ -11,7 +11,6 @@ // compile-flags: -C debug-assertions=no // exec-env:RUST_LOG=conditional-debug-macro-off=4 -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/const-autoderef.rs b/src/test/run-pass/const-autoderef.rs index 1349b7f814..69173e35e2 100644 --- a/src/test/run-pass/const-autoderef.rs +++ b/src/test/run-pass/const-autoderef.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static A: [u8; 1] = ['h' as u8]; static B: u8 = (&A)[0]; diff --git a/src/test/run-pass/const-big-enum.rs b/src/test/run-pass/const-big-enum.rs index 158c695c54..125aefe036 100644 --- a/src/test/run-pass/const-big-enum.rs +++ b/src/test/run-pass/const-big-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar(u32), diff --git a/src/test/run-pass/const-binops.rs b/src/test/run-pass/const-binops.rs index 1a95220cda..a29953bea8 100644 --- a/src/test/run-pass/const-binops.rs +++ b/src/test/run-pass/const-binops.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ - use std::num::Float; let (a, b) = (&$a, &$b); assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); diff --git a/src/test/run-pass/const-block-cross-crate-fn.rs b/src/test/run-pass/const-block-cross-crate-fn.rs index 853e8dc62b..6fa6feffbf 100644 --- a/src/test/run-pass/const-block-cross-crate-fn.rs +++ b/src/test/run-pass/const-block-cross-crate-fn.rs @@ -10,7 +10,6 @@ // aux-build:cci_const_block.rs -// pretty-expanded FIXME #23616 extern crate cci_const_block; diff --git a/src/test/run-pass/const-block-item-macro-codegen.rs b/src/test/run-pass/const-block-item-macro-codegen.rs index b9e8dbf41d..8a4b220a37 100644 --- a/src/test/run-pass/const-block-item-macro-codegen.rs +++ b/src/test/run-pass/const-block-item-macro-codegen.rs @@ -11,7 +11,6 @@ // General test that function items in static blocks // can be generated with a macro. -// pretty-expanded FIXME #23616 struct MyType { desc: &'static str, diff --git a/src/test/run-pass/const-block-item.rs b/src/test/run-pass/const-block-item.rs index 897e538226..b616b1f610 100644 --- a/src/test/run-pass/const-block-item.rs +++ b/src/test/run-pass/const-block-item.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub trait Value { diff --git a/src/test/run-pass/const-block.rs b/src/test/run-pass/const-block.rs index 1337a91fe0..e56d01d7ba 100644 --- a/src/test/run-pass/const-block.rs +++ b/src/test/run-pass/const-block.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![allow(unused_unsafe)] diff --git a/src/test/run-pass/const-cast-ptr-int.rs b/src/test/run-pass/const-cast-ptr-int.rs index bbe3020ea1..e7674f893d 100644 --- a/src/test/run-pass/const-cast-ptr-int.rs +++ b/src/test/run-pass/const-cast-ptr-int.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ptr; diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs index f660dc5fa4..411df2b3e0 100644 --- a/src/test/run-pass/const-cast.rs +++ b/src/test/run-pass/const-cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/const-const.rs b/src/test/run-pass/const-const.rs index d75a5a7eb1..b28017b85a 100644 --- a/src/test/run-pass/const-const.rs +++ b/src/test/run-pass/const-const.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const a: isize = 1; const b: isize = a + 2; diff --git a/src/test/run-pass/const-contents.rs b/src/test/run-pass/const-contents.rs index 2dfb88dee0..0d9d0e0e0a 100644 --- a/src/test/run-pass/const-contents.rs +++ b/src/test/run-pass/const-contents.rs @@ -10,7 +10,6 @@ // Issue #570 -// pretty-expanded FIXME #23616 static lsl : isize = 1 << 2; static add : isize = 1 + 2; diff --git a/src/test/run-pass/const-cross-crate-const.rs b/src/test/run-pass/const-cross-crate-const.rs index e36a55361e..d66c335db2 100644 --- a/src/test/run-pass/const-cross-crate-const.rs +++ b/src/test/run-pass/const-cross-crate-const.rs @@ -10,7 +10,6 @@ // aux-build:cci_const.rs -// pretty-expanded FIXME #23616 extern crate cci_const; static foo: &'static str = cci_const::foopy; diff --git a/src/test/run-pass/const-cross-crate-extern.rs b/src/test/run-pass/const-cross-crate-extern.rs index 98f42f9124..bbe31ceed3 100644 --- a/src/test/run-pass/const-cross-crate-extern.rs +++ b/src/test/run-pass/const-cross-crate-extern.rs @@ -10,7 +10,6 @@ // aux-build:cci_const.rs -// pretty-expanded FIXME #23616 extern crate cci_const; use cci_const::bar; diff --git a/src/test/run-pass/const-deref.rs b/src/test/run-pass/const-deref.rs index 1648332fe2..f5407f0c81 100644 --- a/src/test/run-pass/const-deref.rs +++ b/src/test/run-pass/const-deref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const C: &'static isize = &1000; static D: isize = *C; diff --git a/src/test/run-pass/const-enum-byref-self.rs b/src/test/run-pass/const-enum-byref-self.rs index e99e1aac8a..57470c4a67 100644 --- a/src/test/run-pass/const-enum-byref-self.rs +++ b/src/test/run-pass/const-enum-byref-self.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V, VV(isize) } static C: E = E::V; diff --git a/src/test/run-pass/const-enum-byref.rs b/src/test/run-pass/const-enum-byref.rs index 4905eaace6..e3f1d5d353 100644 --- a/src/test/run-pass/const-enum-byref.rs +++ b/src/test/run-pass/const-enum-byref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V, VV(isize) } static C: E = E::V; diff --git a/src/test/run-pass/const-enum-cast.rs b/src/test/run-pass/const-enum-cast.rs index 3d73933c6f..38f21f7e95 100644 --- a/src/test/run-pass/const-enum-cast.rs +++ b/src/test/run-pass/const-enum-cast.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum A { A1, A2 } enum B { B1=0, B2=2 } diff --git a/src/test/run-pass/const-enum-ptr.rs b/src/test/run-pass/const-enum-ptr.rs index d34b5381df..40a1c99e98 100644 --- a/src/test/run-pass/const-enum-ptr.rs +++ b/src/test/run-pass/const-enum-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V1(isize) } static C: &'static E = &E::V0; diff --git a/src/test/run-pass/const-enum-struct.rs b/src/test/run-pass/const-enum-struct.rs index 71a9703ec3..46c4f82eb9 100644 --- a/src/test/run-pass/const-enum-struct.rs +++ b/src/test/run-pass/const-enum-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } struct S { a: E, b: u16, c: u16 } diff --git a/src/test/run-pass/const-enum-struct2.rs b/src/test/run-pass/const-enum-struct2.rs index ca56cb5b01..e356ecb385 100644 --- a/src/test/run-pass/const-enum-struct2.rs +++ b/src/test/run-pass/const-enum-struct2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } struct S { a: E, b: u16, c: u16 } diff --git a/src/test/run-pass/const-enum-structlike.rs b/src/test/run-pass/const-enum-structlike.rs index 113f20e21e..6c8786dee6 100644 --- a/src/test/run-pass/const-enum-structlike.rs +++ b/src/test/run-pass/const-enum-structlike.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { S0 { s: String }, diff --git a/src/test/run-pass/const-enum-tuple.rs b/src/test/run-pass/const-enum-tuple.rs index 2ab28f5fb2..476defaa52 100644 --- a/src/test/run-pass/const-enum-tuple.rs +++ b/src/test/run-pass/const-enum-tuple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } static C: (E, u16, u16) = (E::V16(0xDEAD), 0x600D, 0xBAD); diff --git a/src/test/run-pass/const-enum-tuple2.rs b/src/test/run-pass/const-enum-tuple2.rs index fe1b2e051c..61043ef75a 100644 --- a/src/test/run-pass/const-enum-tuple2.rs +++ b/src/test/run-pass/const-enum-tuple2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } static C: (E, u16, u16) = (E::V0, 0x600D, 0xBAD); diff --git a/src/test/run-pass/const-enum-tuplestruct.rs b/src/test/run-pass/const-enum-tuplestruct.rs index 7f9de49404..f574508522 100644 --- a/src/test/run-pass/const-enum-tuplestruct.rs +++ b/src/test/run-pass/const-enum-tuplestruct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V16(u16), V32(u32) } struct S(E, u16, u16); diff --git a/src/test/run-pass/const-enum-tuplestruct2.rs b/src/test/run-pass/const-enum-tuplestruct2.rs index 3d7b6c9f49..88cfc0dec7 100644 --- a/src/test/run-pass/const-enum-tuplestruct2.rs +++ b/src/test/run-pass/const-enum-tuplestruct2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V0, V16(u16) } struct S(E, u16, u16); diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index fcaf8b8844..2f1cd8dbf9 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } const C: &'static [E] = &[E::V0, E::V1(0xDEADBEE)]; diff --git a/src/test/run-pass/const-enum-vec-ptr.rs b/src/test/run-pass/const-enum-vec-ptr.rs index 936d72ac65..de94527a60 100644 --- a/src/test/run-pass/const-enum-vec-ptr.rs +++ b/src/test/run-pass/const-enum-vec-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } static C: &'static [E] = &[E::V0, E::V1(0xDEADBEE), E::V0]; diff --git a/src/test/run-pass/const-enum-vector.rs b/src/test/run-pass/const-enum-vector.rs index 6fdf0c3948..8d43a76bc2 100644 --- a/src/test/run-pass/const-enum-vector.rs +++ b/src/test/run-pass/const-enum-vector.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { V1(isize), V0 } static C: [E; 3] = [E::V0, E::V1(0xDEADBEE), E::V0]; diff --git a/src/test/run-pass/const-extern-function.rs b/src/test/run-pass/const-extern-function.rs index ff829711a4..214b0400e8 100644 --- a/src/test/run-pass/const-extern-function.rs +++ b/src/test/run-pass/const-extern-function.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 extern fn foopy() {} diff --git a/src/test/run-pass/const-fn-val.rs b/src/test/run-pass/const-fn-val.rs index 3e1058dc27..85c92dda43 100644 --- a/src/test/run-pass/const-fn-val.rs +++ b/src/test/run-pass/const-fn-val.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo() -> isize { return 0xca7f000d; diff --git a/src/test/run-pass/const-negative.rs b/src/test/run-pass/const-negative.rs index 59b2c3e36a..7f26a97733 100644 --- a/src/test/run-pass/const-negative.rs +++ b/src/test/run-pass/const-negative.rs @@ -10,7 +10,6 @@ // Issue #358 -// pretty-expanded FIXME #23616 static toplevel_mod: isize = -1; diff --git a/src/test/run-pass/const-nullary-enum.rs b/src/test/run-pass/const-nullary-enum.rs index fcad89470d..b3f6549ef0 100644 --- a/src/test/run-pass/const-nullary-enum.rs +++ b/src/test/run-pass/const-nullary-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar, diff --git a/src/test/run-pass/const-nullary-univariant-enum.rs b/src/test/run-pass/const-nullary-univariant-enum.rs index 51926ececc..b1b7f782cd 100644 --- a/src/test/run-pass/const-nullary-univariant-enum.rs +++ b/src/test/run-pass/const-nullary-univariant-enum.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] enum Foo { diff --git a/src/test/run-pass/const-region-ptrs-noncopy.rs b/src/test/run-pass/const-region-ptrs-noncopy.rs index 8932853fbf..9a1f747ce5 100644 --- a/src/test/run-pass/const-region-ptrs-noncopy.rs +++ b/src/test/run-pass/const-region-ptrs-noncopy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type Big = [u64; 8]; struct Pair<'a> { a: isize, b: &'a Big } diff --git a/src/test/run-pass/const-str-ptr.rs b/src/test/run-pass/const-str-ptr.rs index c5ff134ff0..1cdb98a8bc 100644 --- a/src/test/run-pass/const-str-ptr.rs +++ b/src/test/run-pass/const-str-ptr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::{str, string}; diff --git a/src/test/run-pass/const-tuple-struct.rs b/src/test/run-pass/const-tuple-struct.rs index ccf1b06bac..ddc50fc664 100644 --- a/src/test/run-pass/const-tuple-struct.rs +++ b/src/test/run-pass/const-tuple-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Bar(isize, isize); diff --git a/src/test/run-pass/consts-in-patterns.rs b/src/test/run-pass/consts-in-patterns.rs index c2f7cf4d62..36e6e160a3 100644 --- a/src/test/run-pass/consts-in-patterns.rs +++ b/src/test/run-pass/consts-in-patterns.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const FOO: isize = 10; const BAR: isize = 3; diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index 03bf385125..df7cedd1c2 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -16,34 +16,34 @@ // instead of in std. #![reexport_test_harness_main = "test_main"] -#![feature(old_io, libc, std_misc)] +#![feature(libc, std_misc)] extern crate libc; -use std::old_io::{Process, Command, timer}; -use std::time::Duration; +use std::process::{self, Command, Child, Output, Stdio}; use std::str; use std::sync::mpsc::channel; use std::thread; +use std::time::Duration; -macro_rules! succeed { ($e:expr) => ( - match $e { Ok(..) => {}, Err(e) => panic!("panic: {}", e) } -) } +macro_rules! t { + ($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("error: {}", e) }) +} fn test_destroy_once() { let mut p = sleeper(); - match p.signal_exit() { + match p.kill() { Ok(()) => {} Err(e) => panic!("error: {}", e), } } #[cfg(unix)] -pub fn sleeper() -> Process { +pub fn sleeper() -> Child { Command::new("sleep").arg("1000").spawn().unwrap() } #[cfg(windows)] -pub fn sleeper() -> Process { +pub fn sleeper() -> Child { // There's a `timeout` command on windows, but it doesn't like having // its output piped, so instead just ping ourselves a few times with // gaps in between so we're sure this process is alive for awhile @@ -52,16 +52,12 @@ pub fn sleeper() -> Process { fn test_destroy_twice() { let mut p = sleeper(); - succeed!(p.signal_exit()); // this shouldn't crash... - let _ = p.signal_exit(); // ...and nor should this (and nor should the destructor) + t!(p.kill()); // this shouldn't crash... + let _ = p.kill(); // ...and nor should this (and nor should the destructor) } -pub fn test_destroy_actually_kills(force: bool) { - use std::old_io::process::{Command, ProcessOutput, ExitStatus, ExitSignal}; - use std::old_io::timer; - use libc; - use std::str; - +#[test] +fn test_destroy_actually_kills() { #[cfg(all(unix,not(target_os="android")))] static BLOCK_COMMAND: &'static str = "cat"; @@ -72,36 +68,25 @@ pub fn test_destroy_actually_kills(force: bool) { static BLOCK_COMMAND: &'static str = "cmd"; // this process will stay alive indefinitely trying to read from stdin - let mut p = Command::new(BLOCK_COMMAND).spawn().unwrap(); - - assert!(p.signal(0).is_ok()); + let mut p = Command::new(BLOCK_COMMAND) + .stdin(Stdio::piped()) + .spawn().unwrap(); - if force { - p.signal_kill().unwrap(); - } else { - p.signal_exit().unwrap(); - } + p.kill().unwrap(); // Don't let this test time out, this should be quick - let (tx, rx1) = channel(); - let mut t = timer::Timer::new().unwrap(); - let rx2 = t.oneshot(Duration::milliseconds(1000)); + let (tx, rx) = channel(); thread::spawn(move|| { - select! { - _ = rx2.recv() => unsafe { libc::exit(1) }, - _ = rx1.recv() => {} + thread::sleep_ms(1000); + if rx.try_recv().is_err() { + process::exit(1); } }); - match p.wait().unwrap() { - ExitStatus(..) => panic!("expected a signal"), - ExitSignal(..) => tx.send(()).unwrap(), + let code = p.wait().unwrap().code(); + if cfg!(windows) { + assert!(code.is_some()); + } else { + assert!(code.is_none()); } -} - -fn test_unforced_destroy_actually_kills() { - test_destroy_actually_kills(false); -} - -fn test_forced_destroy_actually_kills() { - test_destroy_actually_kills(true); + tx.send(()); } diff --git a/src/test/run-pass/cross-crate-newtype-struct-pat.rs b/src/test/run-pass/cross-crate-newtype-struct-pat.rs index 986108c5d8..7eae901742 100644 --- a/src/test/run-pass/cross-crate-newtype-struct-pat.rs +++ b/src/test/run-pass/cross-crate-newtype-struct-pat.rs @@ -10,7 +10,6 @@ // aux-build:newtype_struct_xc.rs -// pretty-expanded FIXME #23616 extern crate newtype_struct_xc; diff --git a/src/test/run-pass/cycle-generic-bound.rs b/src/test/run-pass/cycle-generic-bound.rs index 94e4665bb8..86b41284cd 100644 --- a/src/test/run-pass/cycle-generic-bound.rs +++ b/src/test/run-pass/cycle-generic-bound.rs @@ -12,9 +12,7 @@ // pretty-expanded FIXME #23616 -use std::marker::PhantomFn; - -trait Chromosome> : PhantomFn<(Self,X)> { +trait Chromosome> { } fn main() { } diff --git a/src/test/run-pass/deep.rs b/src/test/run-pass/deep.rs index 16636fadbf..f8e690cf29 100644 --- a/src/test/run-pass/deep.rs +++ b/src/test/run-pass/deep.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 fn f(x: isize) -> isize { if x == 1 { return 1; } else { let y: isize = 1 + f(x - 1); return y; } diff --git a/src/test/run-pass/deref-mut-on-ref.rs b/src/test/run-pass/deref-mut-on-ref.rs index 8820003d3b..98441d7daa 100644 --- a/src/test/run-pass/deref-mut-on-ref.rs +++ b/src/test/run-pass/deref-mut-on-ref.rs @@ -10,7 +10,6 @@ // Test that `&mut T` implements `DerefMut` -// pretty-expanded FIXME #23616 use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/deref-on-ref.rs b/src/test/run-pass/deref-on-ref.rs index 84bfbd8229..383c8197f9 100644 --- a/src/test/run-pass/deref-on-ref.rs +++ b/src/test/run-pass/deref-on-ref.rs @@ -10,7 +10,6 @@ // Test that `&T` and `&mut T` implement `Deref` -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/deref-rc.rs b/src/test/run-pass/deref-rc.rs index 761b29258f..b84d78b4f4 100644 --- a/src/test/run-pass/deref-rc.rs +++ b/src/test/run-pass/deref-rc.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::rc::Rc; diff --git a/src/test/run-pass/derive-no-std.rs b/src/test/run-pass/derive-no-std.rs index fbc6c28fd4..0234d7b0b6 100644 --- a/src/test/run-pass/derive-no-std.rs +++ b/src/test/run-pass/derive-no-std.rs @@ -31,7 +31,6 @@ enum Bar { Quux(u32), } -#[derive(FromPrimitive)] enum Baz { A=0, B=5, } fn main() { diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs index 07ad8f706e..b1cd1877a7 100644 --- a/src/test/run-pass/deriving-cmp-generic-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] enum E { diff --git a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs index 5f7d184f19..14f7862ef2 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] enum ES { diff --git a/src/test/run-pass/deriving-cmp-generic-struct.rs b/src/test/run-pass/deriving-cmp-generic-struct.rs index ea0017380b..5c7d806f51 100644 --- a/src/test/run-pass/deriving-cmp-generic-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-struct.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] struct S { diff --git a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs index 702071676b..b7bfb91b27 100644 --- a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #[derive(PartialEq, Eq, PartialOrd, Ord)] struct TS(T,T); diff --git a/src/test/run-pass/deriving-cmp-shortcircuit.rs b/src/test/run-pass/deriving-cmp-shortcircuit.rs index 1669f3fdd3..e22e4767d5 100644 --- a/src/test/run-pass/deriving-cmp-shortcircuit.rs +++ b/src/test/run-pass/deriving-cmp-shortcircuit.rs @@ -12,7 +12,6 @@ // where possible, by having a type that panics when compared as the // second element, so this passes iff the instances shortcircuit. -// pretty-expanded FIXME #23616 use std::cmp::Ordering; diff --git a/src/test/run-pass/deriving-default-box.rs b/src/test/run-pass/deriving-default-box.rs index 574a620ef0..dc31e71aad 100644 --- a/src/test/run-pass/deriving-default-box.rs +++ b/src/test/run-pass/deriving-default-box.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass/deriving-encodable-decodable-box.rs index 6ccedb0ad9..db5a1f3f00 100644 --- a/src/test/run-pass/deriving-encodable-decodable-box.rs +++ b/src/test/run-pass/deriving-encodable-decodable-box.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs index d216062bb2..7cc59edfca 100644 --- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs +++ b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs @@ -11,7 +11,6 @@ // This briefly tests the capability of `Cell` and `RefCell` to implement the // `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]` -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index 105d421b40..10e8ddc41f 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -11,7 +11,6 @@ #![feature(rand, rustc_private)] extern crate serialize; -extern crate rand; mod submod { // if any of these are implemented without global calls for any @@ -20,21 +19,21 @@ mod submod { #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] enum A { A1(usize), A2(isize) } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] struct B { x: usize, y: isize } #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone, - Debug, Rand, + Debug, Encodable, Decodable)] struct C(usize, isize); diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index ce7ba9f25e..287750e505 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(hash)] diff --git a/src/test/run-pass/deriving-primitive.rs b/src/test/run-pass/deriving-primitive.rs deleted file mode 100644 index 4399d741ca..0000000000 --- a/src/test/run-pass/deriving-primitive.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2013-2014 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. - -#![feature(core)] - -use std::num::FromPrimitive; -use std::isize; - -#[derive(PartialEq, FromPrimitive, Debug)] -enum A { - Foo = isize::MAX, - Bar = 1, - Baz = 3, - Qux, -} - -pub fn main() { - let x: Option = FromPrimitive::from_int(isize::MAX); - assert_eq!(x, Some(A::Foo)); - - let x: Option = FromPrimitive::from_int(1); - assert_eq!(x, Some(A::Bar)); - - let x: Option = FromPrimitive::from_int(3); - assert_eq!(x, Some(A::Baz)); - - let x: Option = FromPrimitive::from_int(4); - assert_eq!(x, Some(A::Qux)); - - let x: Option = FromPrimitive::from_int(5); - assert_eq!(x, None); -} diff --git a/src/test/run-pass/deriving-rand.rs b/src/test/run-pass/deriving-rand.rs deleted file mode 100644 index b960c2ddd4..0000000000 --- a/src/test/run-pass/deriving-rand.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013-2014 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. - -// pretty-expanded FIXME #23616 - -#![feature(rand)] - -use std::rand; - -#[derive(Rand)] -struct A; - -#[derive(Rand)] -struct B(isize, isize); - -#[derive(Rand)] -struct C { - x: f64, - y: (u8, u8) -} - -#[derive(Rand)] -enum D { - D0, - D1(usize), - D2 { x: (), y: () } -} - -pub fn main() { - // check there's no segfaults - for _ in 0..20 { - rand::random::(); - rand::random::(); - rand::random::(); - rand::random::(); - } -} diff --git a/src/test/run-pass/destructure-array-1.rs b/src/test/run-pass/destructure-array-1.rs index e2c9608571..0d24f0bd0d 100644 --- a/src/test/run-pass/destructure-array-1.rs +++ b/src/test/run-pass/destructure-array-1.rs @@ -11,7 +11,6 @@ // Ensure that we can do a destructuring bind of a fixed-size array, // even when the element type has a destructor. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/die-macro.rs b/src/test/run-pass/die-macro.rs index 6a81ebe67b..0816e258e8 100644 --- a/src/test/run-pass/die-macro.rs +++ b/src/test/run-pass/die-macro.rs @@ -10,7 +10,6 @@ // Just testing that panic!() type checks in statement or expr -// pretty-expanded FIXME #23616 #![allow(unreachable_code)] diff --git a/src/test/run-pass/discriminant_value.rs b/src/test/run-pass/discriminant_value.rs new file mode 100644 index 0000000000..217e696f09 --- /dev/null +++ b/src/test/run-pass/discriminant_value.rs @@ -0,0 +1,77 @@ +// Copyright 2014 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. + +#![feature(core)] + +extern crate core; +use core::intrinsics::discriminant_value; + +enum CLike1 { + A, + B, + C, + D +} + +enum CLike2 { + A = 5, + B = 2, + C = 19, + D +} + +#[repr(i8)] +enum CLike3 { + A = 5, + B, + C = -1, + D +} + +enum ADT { + First(u32, u32), + Second(u64) +} + +enum NullablePointer { + Something(&'static u32), + Nothing +} + +static CONST : u32 = 0xBEEF; + +pub fn main() { + unsafe { + + assert_eq!(discriminant_value(&CLike1::A), 0); + assert_eq!(discriminant_value(&CLike1::B), 1); + assert_eq!(discriminant_value(&CLike1::C), 2); + assert_eq!(discriminant_value(&CLike1::D), 3); + + assert_eq!(discriminant_value(&CLike2::A), 5); + assert_eq!(discriminant_value(&CLike2::B), 2); + assert_eq!(discriminant_value(&CLike2::C), 19); + assert_eq!(discriminant_value(&CLike2::D), 20); + + assert_eq!(discriminant_value(&CLike3::A), 5); + assert_eq!(discriminant_value(&CLike3::B), 6); + assert_eq!(discriminant_value(&CLike3::C), -1_i8 as u64); + assert_eq!(discriminant_value(&CLike3::D), 0); + + assert_eq!(discriminant_value(&ADT::First(0,0)), 0); + assert_eq!(discriminant_value(&ADT::Second(5)), 1); + + assert_eq!(discriminant_value(&NullablePointer::Nothing), 1); + assert_eq!(discriminant_value(&NullablePointer::Something(&CONST)), 0); + + assert_eq!(discriminant_value(&10), 0); + assert_eq!(discriminant_value(&"test"), 0); + } +} diff --git a/src/test/run-pass/div-mod.rs b/src/test/run-pass/div-mod.rs index 237cfe19dc..b6cae71df8 100644 --- a/src/test/run-pass/div-mod.rs +++ b/src/test/run-pass/div-mod.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let x: isize = 15; diff --git a/src/test/run-pass/drop-flag-sanity-check.rs b/src/test/run-pass/drop-flag-sanity-check.rs index 02f6cc70fd..f9e1b651a4 100644 --- a/src/test/run-pass/drop-flag-sanity-check.rs +++ b/src/test/run-pass/drop-flag-sanity-check.rs @@ -17,10 +17,8 @@ // // See also drop-flag-skip-sanity-check.rs. -#![feature(old_io)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; fn main() { let args: Vec = env::args().collect(); diff --git a/src/test/run-pass/drop-flag-skip-sanity-check.rs b/src/test/run-pass/drop-flag-skip-sanity-check.rs index 7066b4017a..4a6c8ce70d 100644 --- a/src/test/run-pass/drop-flag-skip-sanity-check.rs +++ b/src/test/run-pass/drop-flag-skip-sanity-check.rs @@ -17,10 +17,8 @@ // // See also drop-flag-sanity-check.rs. -#![feature(old_io)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; fn main() { let args: Vec = env::args().collect(); @@ -28,9 +26,9 @@ fn main() { return test(); } - let mut p = Command::new(&args[0]).arg("test").spawn().unwrap(); + let s = Command::new(&args[0]).arg("test").status().unwrap(); // Invocatinn should succeed as drop-flag sanity check is skipped. - assert!(p.wait().unwrap().success()); + assert!(s.success()); } #[derive(Debug)] @@ -65,5 +63,4 @@ fn test() { // drop-glue should detect the corruption of (at least one of) // the drop-flags. } - println!("We should never get here."); } diff --git a/src/test/run-pass/drop-struct-as-object.rs b/src/test/run-pass/drop-struct-as-object.rs index efb98160a3..33d5c72772 100644 --- a/src/test/run-pass/drop-struct-as-object.rs +++ b/src/test/run-pass/drop-struct-as-object.rs @@ -11,7 +11,6 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/drop-with-type-ascription-1.rs b/src/test/run-pass/drop-with-type-ascription-1.rs index ea9edff494..9dd458344c 100644 --- a/src/test/run-pass/drop-with-type-ascription-1.rs +++ b/src/test/run-pass/drop-with-type-ascription-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(str_words)] diff --git a/src/test/run-pass/drop-with-type-ascription-2.rs b/src/test/run-pass/drop-with-type-ascription-2.rs index 3d4af80e30..cb3712dea3 100644 --- a/src/test/run-pass/drop-with-type-ascription-2.rs +++ b/src/test/run-pass/drop-with-type-ascription-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass/dropck_tarena_sound_drop.rs index df29b8e10c..6ccf6c2fd6 100644 --- a/src/test/run-pass/dropck_tarena_sound_drop.rs +++ b/src/test/run-pass/dropck_tarena_sound_drop.rs @@ -16,7 +16,6 @@ // shows a similar setup, but restricts `f` so that the struct `C<'a>` // is force-fed a lifetime equal to that of the borrowed arena. -// pretty-expanded FIXME #23616 #![allow(unstable)] #![feature(unsafe_destructor, rustc_private)] diff --git a/src/test/run-pass/dst-deref-mut.rs b/src/test/run-pass/dst-deref-mut.rs index 3b2b7493fd..b031c82a07 100644 --- a/src/test/run-pass/dst-deref-mut.rs +++ b/src/test/run-pass/dst-deref-mut.rs @@ -10,7 +10,6 @@ // Test that a custom deref with a fat pointer return type does not ICE -// pretty-expanded FIXME #23616 use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/dst-deref.rs b/src/test/run-pass/dst-deref.rs index c8e658beef..c4666d05fb 100644 --- a/src/test/run-pass/dst-deref.rs +++ b/src/test/run-pass/dst-deref.rs @@ -10,7 +10,6 @@ // Test that a custom deref with a fat pointer return type does not ICE -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/dst-index.rs b/src/test/run-pass/dst-index.rs index df4cd74740..34a187fa6f 100644 --- a/src/test/run-pass/dst-index.rs +++ b/src/test/run-pass/dst-index.rs @@ -11,7 +11,6 @@ // Test that overloaded index expressions with DST result types // work and don't ICE. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index 5e0e5bd03f..d899de9164 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -10,7 +10,6 @@ // Test DST raw pointers -// pretty-expanded FIXME #23616 trait Trait { fn foo(&self) -> isize; diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs index 9bf286c434..c5da5fc0c1 100644 --- a/src/test/run-pass/dst-struct-sole.rs +++ b/src/test/run-pass/dst-struct-sole.rs @@ -10,7 +10,6 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. -// pretty-expanded FIXME #23616 struct Fat { ptr: T @@ -80,7 +79,7 @@ pub fn main() { // Zero size vec. let f5: &Fat<[isize]> = &Fat { ptr: [] }; - assert!(f5.ptr.len() == 0); + assert!(f5.ptr.is_empty()); let f5: &Fat<[Bar]> = &Fat { ptr: [] }; - assert!(f5.ptr.len() == 0); + assert!(f5.ptr.is_empty()); } diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 5198dd43d6..92253d8159 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] @@ -99,9 +98,9 @@ pub fn main() { // Zero size vec. let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [] }; - assert!(f5.ptr.len() == 0); + assert!(f5.ptr.is_empty()); let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] }; - assert!(f5.ptr.len() == 0); + assert!(f5.ptr.is_empty()); // Deeply nested. let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index 370bc28822..4d2b50c08e 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/early-ret-binop-add.rs b/src/test/run-pass/early-ret-binop-add.rs index 7bd292e66f..0a490466ef 100644 --- a/src/test/run-pass/early-ret-binop-add.rs +++ b/src/test/run-pass/early-ret-binop-add.rs @@ -10,8 +10,8 @@ // pretty-expanded FIXME #23616 -use std::num::Int; +use std::ops::Add; -fn wsucc(n: T) -> T { n + { return n } } +fn wsucc + Copy>(n: T) -> T { n + { return n } } pub fn main() { } diff --git a/src/test/run-pass/else-if.rs b/src/test/run-pass/else-if.rs index 79c2f45067..afc1d200b2 100644 --- a/src/test/run-pass/else-if.rs +++ b/src/test/run-pass/else-if.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { if 1 == 2 { diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs index cec528fa04..af6e321e40 100644 --- a/src/test/run-pass/empty-allocation-non-null.rs +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -10,7 +10,6 @@ // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. -// pretty-expanded FIXME #23616 pub fn main() { assert!(Some(Box::new(())).is_some()); diff --git a/src/test/run-pass/enum-alignment.rs b/src/test/run-pass/enum-alignment.rs index df779d0d71..827894f8f3 100644 --- a/src/test/run-pass/enum-alignment.rs +++ b/src/test/run-pass/enum-alignment.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/enum-clike-ffi-as-int.rs b/src/test/run-pass/enum-clike-ffi-as-int.rs index f129a51534..8be3634c88 100644 --- a/src/test/run-pass/enum-clike-ffi-as-int.rs +++ b/src/test/run-pass/enum-clike-ffi-as-int.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /*! * C-like enums have to be represented as LLVM ints, not wrapped in a diff --git a/src/test/run-pass/enum-discr.rs b/src/test/run-pass/enum-discr.rs index 5c01d544cf..1ff6370136 100644 --- a/src/test/run-pass/enum-discr.rs +++ b/src/test/run-pass/enum-discr.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Animal { Cat = 0, diff --git a/src/test/run-pass/enum-discrim-autosizing.rs b/src/test/run-pass/enum-discrim-autosizing.rs index 239f9821b9..99e44735d0 100644 --- a/src/test/run-pass/enum-discrim-autosizing.rs +++ b/src/test/run-pass/enum-discrim-autosizing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/enum-discrim-manual-sizing.rs b/src/test/run-pass/enum-discrim-manual-sizing.rs index b23cfa9f32..edad5cc165 100644 --- a/src/test/run-pass/enum-discrim-manual-sizing.rs +++ b/src/test/run-pass/enum-discrim-manual-sizing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/enum-disr-val-pretty.rs b/src/test/run-pass/enum-disr-val-pretty.rs index 9a2f45d007..cf66725178 100644 --- a/src/test/run-pass/enum-disr-val-pretty.rs +++ b/src/test/run-pass/enum-disr-val-pretty.rs @@ -10,7 +10,6 @@ // pp-exact -// pretty-expanded FIXME #23616 enum color { red = 1, green, blue, imaginary = -1, } diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 9fc799a97f..499d131947 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/enum-nullable-const-null-with-fields.rs b/src/test/run-pass/enum-nullable-const-null-with-fields.rs index 3a7c7ea9a7..1342c4e104 100644 --- a/src/test/run-pass/enum-nullable-const-null-with-fields.rs +++ b/src/test/run-pass/enum-nullable-const-null-with-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::result::Result; use std::result::Result::Ok; diff --git a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs index 99554aafb0..c8a1047cfa 100644 --- a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs +++ b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/env-home-dir.rs b/src/test/run-pass/env-home-dir.rs index 7fb9611212..efe7272981 100644 --- a/src/test/run-pass/env-home-dir.rs +++ b/src/test/run-pass/env-home-dir.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(path)] diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs index 33bc6c596d..d86f63c9cb 100644 --- a/src/test/run-pass/env-vars.rs +++ b/src/test/run-pass/env-vars.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::env::*; diff --git a/src/test/run-pass/eq-multidispatch.rs b/src/test/run-pass/eq-multidispatch.rs index 3ca254021e..bf8b089a83 100644 --- a/src/test/run-pass/eq-multidispatch.rs +++ b/src/test/run-pass/eq-multidispatch.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] struct Bar; diff --git a/src/test/run-pass/estr-uniq.rs b/src/test/run-pass/estr-uniq.rs index 0b24658a8f..4dfb154184 100644 --- a/src/test/run-pass/estr-uniq.rs +++ b/src/test/run-pass/estr-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/exec-env.rs b/src/test/run-pass/exec-env.rs index a249307324..d17056e6d7 100644 --- a/src/test/run-pass/exec-env.rs +++ b/src/test/run-pass/exec-env.rs @@ -10,7 +10,6 @@ // exec-env:TEST_EXEC_ENV=22 -// pretty-expanded FIXME #23616 use std::env; diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index ee50d3bdf0..1b50d3028b 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index 08ea638f93..4021ae89e3 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/explicit-self.rs b/src/test/run-pass/explicit-self.rs index b81090555e..d2a0d60eb6 100644 --- a/src/test/run-pass/explicit-self.rs +++ b/src/test/run-pass/explicit-self.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/exponential-notation.rs b/src/test/run-pass/exponential-notation.rs deleted file mode 100644 index 7e947c0be4..0000000000 --- a/src/test/run-pass/exponential-notation.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 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. - -// pretty-expanded FIXME #23616 - -#![feature(std_misc)] - -use std::num::strconv::ExponentFormat::{ExpBin, ExpDec}; -use std::num::strconv::SignificantDigits::DigMax; -use std::num::strconv::SignFormat::{SignAll, SignNeg}; -use std::num::strconv::float_to_str_common as to_string; - -macro_rules! t { - ($a:expr, $b:expr) => { { let (r, _) = $a; assert_eq!(r, $b.to_string()); } } -} - -pub fn main() { - // Basic usage - t!(to_string(1.2345678e-5f64, 10, true, SignNeg, DigMax(6), ExpDec, false), - "1.234568e-5"); - - // Hexadecimal output - t!(to_string(7.281738281250e+01f64, 16, true, SignAll, DigMax(6), ExpBin, false), - "+1.2345p+6"); - t!(to_string(-1.777768135071e-02f64, 16, true, SignAll, DigMax(6), ExpBin, false), - "-1.2345p-6"); - - // Some denormals - t!(to_string(4.9406564584124654e-324f64, 10, true, SignNeg, DigMax(6), ExpBin, false), - "1p-1074"); - t!(to_string(2.2250738585072009e-308f64, 10, true, SignNeg, DigMax(6), ExpBin, false), - "1p-1022"); -} diff --git a/src/test/run-pass/expr-block-fn.rs b/src/test/run-pass/expr-block-fn.rs index c88721471b..67e41aad69 100644 --- a/src/test/run-pass/expr-block-fn.rs +++ b/src/test/run-pass/expr-block-fn.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 fn test_fn() { fn ten() -> isize { return 10; } diff --git a/src/test/run-pass/expr-block-generic-unique2.rs b/src/test/run-pass/expr-block-generic-unique2.rs index bd29367739..5477a9227a 100644 --- a/src/test/run-pass/expr-block-generic-unique2.rs +++ b/src/test/run-pass/expr-block-generic-unique2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-block-generic.rs b/src/test/run-pass/expr-block-generic.rs index d26c6e62f5..8795962beb 100644 --- a/src/test/run-pass/expr-block-generic.rs +++ b/src/test/run-pass/expr-block-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; diff --git a/src/test/run-pass/expr-block-slot.rs b/src/test/run-pass/expr-block-slot.rs index 57b5a426f5..d9b4c95bc2 100644 --- a/src/test/run-pass/expr-block-slot.rs +++ b/src/test/run-pass/expr-block-slot.rs @@ -10,7 +10,6 @@ // Regression test for issue #377 -// pretty-expanded FIXME #23616 struct A { a: isize } struct V { v: isize } diff --git a/src/test/run-pass/expr-block-unique.rs b/src/test/run-pass/expr-block-unique.rs index 496a575c6c..7ad0241860 100644 --- a/src/test/run-pass/expr-block-unique.rs +++ b/src/test/run-pass/expr-block-unique.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-block.rs b/src/test/run-pass/expr-block.rs index 64f86237ab..38be041938 100644 --- a/src/test/run-pass/expr-block.rs +++ b/src/test/run-pass/expr-block.rs @@ -13,7 +13,6 @@ // Tests for standalone blocks as expressions -// pretty-expanded FIXME #23616 fn test_basic() { let rs: bool = { true }; assert!((rs)); } diff --git a/src/test/run-pass/expr-copy.rs b/src/test/run-pass/expr-copy.rs index ca394f991f..99e74a6b85 100644 --- a/src/test/run-pass/expr-copy.rs +++ b/src/test/run-pass/expr-copy.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn f(arg: &mut A) { arg.a = 100; diff --git a/src/test/run-pass/expr-fn.rs b/src/test/run-pass/expr-fn.rs index 0c9151cec7..aeca388d31 100644 --- a/src/test/run-pass/expr-fn.rs +++ b/src/test/run-pass/expr-fn.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test_int() { fn f() -> isize { 10 } diff --git a/src/test/run-pass/expr-if-generic.rs b/src/test/run-pass/expr-if-generic.rs index 47e79de6b1..94c6b70bb6 100644 --- a/src/test/run-pass/expr-if-generic.rs +++ b/src/test/run-pass/expr-if-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_generic(expected: T, not_expected: T, eq: F) where T: Clone, diff --git a/src/test/run-pass/expr-if-panic-all.rs b/src/test/run-pass/expr-if-panic-all.rs index 1e631c2047..43110533b6 100644 --- a/src/test/run-pass/expr-if-panic-all.rs +++ b/src/test/run-pass/expr-if-panic-all.rs @@ -10,7 +10,6 @@ // When all branches of an if expression result in panic, the entire if // expression results in panic. -// pretty-expanded FIXME #23616 pub fn main() { let _x = if true { diff --git a/src/test/run-pass/expr-if-panic.rs b/src/test/run-pass/expr-if-panic.rs index e8594db803..c7f10b66ca 100644 --- a/src/test/run-pass/expr-if-panic.rs +++ b/src/test/run-pass/expr-if-panic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test_if_panic() { let x = if false { panic!() } else { 10 }; diff --git a/src/test/run-pass/expr-if-unique.rs b/src/test/run-pass/expr-if-unique.rs index 99c5053588..12000fd54e 100644 --- a/src/test/run-pass/expr-if-unique.rs +++ b/src/test/run-pass/expr-if-unique.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-if.rs b/src/test/run-pass/expr-if.rs index 345f17707c..e8458e3201 100644 --- a/src/test/run-pass/expr-if.rs +++ b/src/test/run-pass/expr-if.rs @@ -13,7 +13,6 @@ // Tests for if as expressions -// pretty-expanded FIXME #23616 fn test_if() { let rs: bool = if true { true } else { false }; assert!((rs)); } diff --git a/src/test/run-pass/expr-match-generic-unique1.rs b/src/test/run-pass/expr-match-generic-unique1.rs index 7cd0f6a758..738fcecb2e 100644 --- a/src/test/run-pass/expr-match-generic-unique1.rs +++ b/src/test/run-pass/expr-match-generic-unique1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match-generic-unique2.rs b/src/test/run-pass/expr-match-generic-unique2.rs index 95f47d005d..88ea241524 100644 --- a/src/test/run-pass/expr-match-generic-unique2.rs +++ b/src/test/run-pass/expr-match-generic-unique2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match-generic.rs b/src/test/run-pass/expr-match-generic.rs index f8e82de9a0..509106289d 100644 --- a/src/test/run-pass/expr-match-generic.rs +++ b/src/test/run-pass/expr-match-generic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 type compare = extern "Rust" fn(T, T) -> bool; diff --git a/src/test/run-pass/expr-match-panic-all.rs b/src/test/run-pass/expr-match-panic-all.rs index 664ead10aa..e712d552a8 100644 --- a/src/test/run-pass/expr-match-panic-all.rs +++ b/src/test/run-pass/expr-match-panic-all.rs @@ -13,7 +13,6 @@ // When all branches of a match expression result in panic, the entire // match expression results in panic. -// pretty-expanded FIXME #23616 pub fn main() { let _x = diff --git a/src/test/run-pass/expr-match-panic.rs b/src/test/run-pass/expr-match-panic.rs index 40e7a6175c..89dc7b09c7 100644 --- a/src/test/run-pass/expr-match-panic.rs +++ b/src/test/run-pass/expr-match-panic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test_simple() { let r = match true { true => { true } false => { panic!() } }; diff --git a/src/test/run-pass/expr-match-unique.rs b/src/test/run-pass/expr-match-unique.rs index 51eda4c766..e752c20a51 100644 --- a/src/test/run-pass/expr-match-unique.rs +++ b/src/test/run-pass/expr-match-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/expr-match.rs b/src/test/run-pass/expr-match.rs index 2282391ef6..580ee52ed3 100644 --- a/src/test/run-pass/expr-match.rs +++ b/src/test/run-pass/expr-match.rs @@ -13,7 +13,6 @@ // Tests for using match as an expression -// pretty-expanded FIXME #23616 fn test_basic() { let mut rs: bool = match true { true => { true } false => { false } }; diff --git a/src/test/run-pass/ext-expand-inner-exprs.rs b/src/test/run-pass/ext-expand-inner-exprs.rs index 46cd73e115..90ca31e80b 100644 --- a/src/test/run-pass/ext-expand-inner-exprs.rs +++ b/src/test/run-pass/ext-expand-inner-exprs.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static FOO : &'static str = concat!(concat!("hel", "lo"), "world"); diff --git a/src/test/run-pass/exterior.rs b/src/test/run-pass/exterior.rs index 9a039e8bc3..3474e2eefb 100644 --- a/src/test/run-pass/exterior.rs +++ b/src/test/run-pass/exterior.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index 198745f5b1..b35095171e 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -42,7 +42,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { // Make sure we're on a task with small Rust stacks (main currently // has a large stack) - thread::scoped(move|| { + thread::spawn(move|| { let result = count(1000); println!("result = {}", result); assert_eq!(result, 1000); diff --git a/src/test/run-pass/extern-call-direct.rs b/src/test/run-pass/extern-call-direct.rs index 38cd4a8d79..ec6b6c8d39 100644 --- a/src/test/run-pass/extern-call-direct.rs +++ b/src/test/run-pass/extern-call-direct.rs @@ -10,7 +10,6 @@ // Test direct calls to extern fns. -// pretty-expanded FIXME #23616 extern fn f(x: usize) -> usize { x * 2 } diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index e8c9bc7633..3993868068 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -46,9 +46,9 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { pub fn main() { // Make sure we're on a task with small Rust stacks (main currently // has a large stack) - let _t = thread::scoped(move|| { + thread::spawn(move|| { let result = count(12); println!("result = {}", result); assert_eq!(result, 2048); - }); + }).join(); } diff --git a/src/test/run-pass/extern-compare-with-return-type.rs b/src/test/run-pass/extern-compare-with-return-type.rs index 09411c9c6e..6535ae2fca 100644 --- a/src/test/run-pass/extern-compare-with-return-type.rs +++ b/src/test/run-pass/extern-compare-with-return-type.rs @@ -10,7 +10,6 @@ // Tests that we can compare various kinds of extern fn signatures. -// pretty-expanded FIXME #23616 extern fn voidret1() {} extern fn voidret2() {} diff --git a/src/test/run-pass/extern-methods.rs b/src/test/run-pass/extern-methods.rs index 246f65931b..421b19f286 100644 --- a/src/test/run-pass/extern-methods.rs +++ b/src/test/run-pass/extern-methods.rs @@ -8,13 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(core)] - -use std::marker::MarkerTrait; - -trait A : MarkerTrait { +trait A { extern "fastcall" fn test1(i: i32); extern fn test2(i: i32); } diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index bbdf5cf64a..e75aa2d72c 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -10,7 +10,6 @@ // Test a function that takes/returns a u8. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index 24c461f43a..e92f9b6a1a 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index f93d7a3ff9..0753ea1bcf 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -10,7 +10,6 @@ // Test a function that takes/returns a u32. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 961a3dce16..89faa3bb47 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -10,7 +10,6 @@ // Test a call to a function that takes/returns a u64. -// pretty-expanded FIXME #23616 #[link(name = "rust_test_helpers")] extern { diff --git a/src/test/run-pass/extern-return-TwoU16s.rs b/src/test/run-pass/extern-return-TwoU16s.rs index f149a13462..3c58646e0c 100644 --- a/src/test/run-pass/extern-return-TwoU16s.rs +++ b/src/test/run-pass/extern-return-TwoU16s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU16s { one: u16, two: u16 diff --git a/src/test/run-pass/extern-return-TwoU32s.rs b/src/test/run-pass/extern-return-TwoU32s.rs index 4e9c44ef75..0eb6be2d68 100644 --- a/src/test/run-pass/extern-return-TwoU32s.rs +++ b/src/test/run-pass/extern-return-TwoU32s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU32s { one: u32, two: u32 diff --git a/src/test/run-pass/extern-return-TwoU64s.rs b/src/test/run-pass/extern-return-TwoU64s.rs index fffd77fa89..d5eab86351 100644 --- a/src/test/run-pass/extern-return-TwoU64s.rs +++ b/src/test/run-pass/extern-return-TwoU64s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU64s { one: u64, two: u64 diff --git a/src/test/run-pass/extern-return-TwoU8s.rs b/src/test/run-pass/extern-return-TwoU8s.rs index fdf43d4332..d8f476bcd0 100644 --- a/src/test/run-pass/extern-return-TwoU8s.rs +++ b/src/test/run-pass/extern-return-TwoU8s.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub struct TwoU8s { one: u8, two: u8 diff --git a/src/test/run-pass/extern-take-value.rs b/src/test/run-pass/extern-take-value.rs index c016e4e62f..7ef87b9409 100644 --- a/src/test/run-pass/extern-take-value.rs +++ b/src/test/run-pass/extern-take-value.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 extern fn f() { } diff --git a/src/test/run-pass/extoption_env-not-defined.rs b/src/test/run-pass/extoption_env-not-defined.rs index aaa8f6cf26..352f68da98 100644 --- a/src/test/run-pass/extoption_env-not-defined.rs +++ b/src/test/run-pass/extoption_env-not-defined.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert!(option_env!("__HOPEFULLY_DOESNT_EXIST__").is_none()); diff --git a/src/test/run-pass/fds-are-cloexec.rs b/src/test/run-pass/fds-are-cloexec.rs new file mode 100644 index 0000000000..3be47e8430 --- /dev/null +++ b/src/test/run-pass/fds-are-cloexec.rs @@ -0,0 +1,73 @@ +// 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. + +// ignore-windows +// ignore-android + +#![feature(libc)] + +extern crate libc; + +use std::env; +use std::fs::{self, File}; +use std::io; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::prelude::*; +use std::process::Command; +use std::thread; + +fn main() { + let args = env::args().collect::>(); + if args.len() == 1 { + parent() + } else { + child(&args) + } +} + +fn parent() { + let file = File::open("Makefile").unwrap(); + let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap(); + let tcp2 = tcp1.try_clone().unwrap(); + let addr = tcp1.local_addr().unwrap(); + let t = thread::spawn(move || TcpStream::connect(addr).unwrap()); + let tcp3 = tcp1.accept().unwrap().0; + let tcp4 = t.join().unwrap(); + let tcp5 = tcp3.try_clone().unwrap(); + let tcp6 = tcp4.try_clone().unwrap(); + let udp1 = UdpSocket::bind("127.0.0.1:0").unwrap(); + let udp2 = udp1.try_clone().unwrap(); + + let status = Command::new(env::args().next().unwrap()) + .arg(file.as_raw_fd().to_string()) + .arg(tcp1.as_raw_fd().to_string()) + .arg(tcp2.as_raw_fd().to_string()) + .arg(tcp3.as_raw_fd().to_string()) + .arg(tcp4.as_raw_fd().to_string()) + .arg(tcp5.as_raw_fd().to_string()) + .arg(tcp6.as_raw_fd().to_string()) + .arg(udp1.as_raw_fd().to_string()) + .arg(udp2.as_raw_fd().to_string()) + .status() + .unwrap(); + assert!(status.success()); +} + +fn child(args: &[String]) { + let mut b = [0u8; 2]; + for arg in &args[1..] { + let fd: libc::c_int = arg.parse().unwrap(); + unsafe { + assert_eq!(libc::read(fd, b.as_mut_ptr() as *mut _, 2), -1); + assert_eq!(io::Error::last_os_error().raw_os_error(), + Some(libc::EBADF)); + } + } +} diff --git a/src/test/run-pass/field-destruction-order.rs b/src/test/run-pass/field-destruction-order.rs index aab32a7e7b..624167db36 100644 --- a/src/test/run-pass/field-destruction-order.rs +++ b/src/test/run-pass/field-destruction-order.rs @@ -21,7 +21,6 @@ // declarations, but we currently run them top-to-bottom. I don't think the // order really matters that much as long as we define what it is. -// pretty-expanded FIXME #23616 struct A; struct B; diff --git a/src/test/run-pass/fixed_length_copy.rs b/src/test/run-pass/fixed_length_copy.rs index 019537a2ab..eefd944753 100644 --- a/src/test/run-pass/fixed_length_copy.rs +++ b/src/test/run-pass/fixed_length_copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let arr = [1,2,3]; diff --git a/src/test/run-pass/float-nan.rs b/src/test/run-pass/float-nan.rs index b375f12208..856599431f 100644 --- a/src/test/run-pass/float-nan.rs +++ b/src/test/run-pass/float-nan.rs @@ -8,18 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(std_misc)] - -use std::num::Float; +use std::f64; pub fn main() { - let nan: f64 = Float::nan(); + let nan: f64 = f64::NAN; assert!((nan).is_nan()); - let inf: f64 = Float::infinity(); - let neg_inf: f64 = Float::neg_infinity(); + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = -f64::INFINITY; assert_eq!(-inf, neg_inf); assert!( nan != nan); diff --git a/src/test/run-pass/float2.rs b/src/test/run-pass/float2.rs index f84cbe5235..e9f6e0f51b 100644 --- a/src/test/run-pass/float2.rs +++ b/src/test/run-pass/float2.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let a = 1.5e6f64; diff --git a/src/test/run-pass/floatlits.rs b/src/test/run-pass/floatlits.rs index d45c689bfd..d133f3463a 100644 --- a/src/test/run-pass/floatlits.rs +++ b/src/test/run-pass/floatlits.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let f = 4.999999999999f64; diff --git a/src/test/run-pass/fmt-pointer-trait.rs b/src/test/run-pass/fmt-pointer-trait.rs new file mode 100644 index 0000000000..96f31891f2 --- /dev/null +++ b/src/test/run-pass/fmt-pointer-trait.rs @@ -0,0 +1,35 @@ +// 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. + +#![feature(libc)] +extern crate libc; +use std::ptr; +use std::rc::Rc; +use std::sync::Arc; + +fn main() { + let p: *const libc::c_void = ptr::null(); + let rc = Rc::new(1usize); + let arc = Arc::new(1usize); + let b = Box::new("hi"); + + let _ = format!("{:p}{:p}{:p}", + rc, arc, b); + + if cfg!(target_pointer_width = "32") { + assert_eq!(format!("{:#p}", p), + "0x00000000"); + } else { + assert_eq!(format!("{:#p}", p), + "0x0000000000000000"); + } + assert_eq!(format!("{:p}", p), + "0x0"); +} diff --git a/src/test/run-pass/fn-bare-assign.rs b/src/test/run-pass/fn-bare-assign.rs index d83dc78580..2d3d4cbffd 100644 --- a/src/test/run-pass/fn-bare-assign.rs +++ b/src/test/run-pass/fn-bare-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(i: isize, called: &mut bool) { assert_eq!(i, 10); diff --git a/src/test/run-pass/fn-bare-size.rs b/src/test/run-pass/fn-bare-size.rs index 117cf13584..3ed4f103af 100644 --- a/src/test/run-pass/fn-bare-size.rs +++ b/src/test/run-pass/fn-bare-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/fn-bare-spawn.rs b/src/test/run-pass/fn-bare-spawn.rs index 0a3c891627..e6ee77cb62 100644 --- a/src/test/run-pass/fn-bare-spawn.rs +++ b/src/test/run-pass/fn-bare-spawn.rs @@ -10,7 +10,6 @@ // This is what the signature to spawn should look like with bare functions -// pretty-expanded FIXME #23616 fn spawn(val: T, f: fn(T)) { f(val); diff --git a/src/test/run-pass/fn-item-type-cast.rs b/src/test/run-pass/fn-item-type-cast.rs index f8b1582c51..9a8a8d4782 100644 --- a/src/test/run-pass/fn-item-type-cast.rs +++ b/src/test/run-pass/fn-item-type-cast.rs @@ -10,7 +10,6 @@ // Test explicit coercions from a fn item type to a fn pointer type. -// pretty-expanded FIXME #23616 fn foo(x: isize) -> isize { x * 2 } fn bar(x: isize) -> isize { x * 4 } diff --git a/src/test/run-pass/fn-pattern-expected-type.rs b/src/test/run-pass/fn-pattern-expected-type.rs index 352d0b13c6..2e9607602f 100644 --- a/src/test/run-pass/fn-pattern-expected-type.rs +++ b/src/test/run-pass/fn-pattern-expected-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let f = |(x, y): (isize, isize)| { diff --git a/src/test/run-pass/for-destruct.rs b/src/test/run-pass/for-destruct.rs index 9d8c432e98..963d34a2d2 100644 --- a/src/test/run-pass/for-destruct.rs +++ b/src/test/run-pass/for-destruct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Pair { x: isize, y: isize } diff --git a/src/test/run-pass/for-loop-goofiness.rs b/src/test/run-pass/for-loop-goofiness.rs index 4b6b6dcf1d..411183e4f7 100644 --- a/src/test/run-pass/for-loop-goofiness.rs +++ b/src/test/run-pass/for-loop-goofiness.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum BogusOption { None, diff --git a/src/test/run-pass/for-loop-into-iterator.rs b/src/test/run-pass/for-loop-into-iterator.rs index 109ca26056..7efd15f222 100644 --- a/src/test/run-pass/for-loop-into-iterator.rs +++ b/src/test/run-pass/for-loop-into-iterator.rs @@ -10,7 +10,6 @@ // Test that for loops can do what RFC #235 claims -// pretty-expanded FIXME #23616 fn main() { let mut v = vec![1]; diff --git a/src/test/run-pass/for-loop-panic.rs b/src/test/run-pass/for-loop-panic.rs index 908932fe39..001ca1a02f 100644 --- a/src/test/run-pass/for-loop-panic.rs +++ b/src/test/run-pass/for-loop-panic.rs @@ -9,6 +9,5 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x: Vec = Vec::new(); for _ in &x { panic!("moop"); } } diff --git a/src/test/run-pass/foreach-external-iterators-break.rs b/src/test/run-pass/foreach-external-iterators-break.rs index bc04125989..bfc0d6cf9d 100644 --- a/src/test/run-pass/foreach-external-iterators-break.rs +++ b/src/test/run-pass/foreach-external-iterators-break.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs index cc02ee1459..cedb960143 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/foreach-external-iterators-hashmap.rs b/src/test/run-pass/foreach-external-iterators-hashmap.rs index 065e4cfb76..79304fce5c 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/foreach-external-iterators-loop.rs b/src/test/run-pass/foreach-external-iterators-loop.rs index 60cfc9be07..7248537d6a 100644 --- a/src/test/run-pass/foreach-external-iterators-loop.rs +++ b/src/test/run-pass/foreach-external-iterators-loop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators-nested.rs b/src/test/run-pass/foreach-external-iterators-nested.rs index a075c08b73..87aa3d8400 100644 --- a/src/test/run-pass/foreach-external-iterators-nested.rs +++ b/src/test/run-pass/foreach-external-iterators-nested.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-external-iterators.rs b/src/test/run-pass/foreach-external-iterators.rs index 2248132d82..d1fe98f543 100644 --- a/src/test/run-pass/foreach-external-iterators.rs +++ b/src/test/run-pass/foreach-external-iterators.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = [1; 100]; diff --git a/src/test/run-pass/foreach-nested.rs b/src/test/run-pass/foreach-nested.rs index 075539b621..60068185f5 100644 --- a/src/test/run-pass/foreach-nested.rs +++ b/src/test/run-pass/foreach-nested.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn two(mut it: F) where F: FnMut(isize) { it(0); it(1); } diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 5db83d50b6..a9001a3cdc 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc, libc)] diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs index 7883c22f90..d3d872620c 100644 --- a/src/test/run-pass/foreign-fn-with-byval.rs +++ b/src/test/run-pass/foreign-fn-with-byval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] pub struct S { diff --git a/src/test/run-pass/format-nan.rs b/src/test/run-pass/format-nan.rs index bdbbeaa951..9bbd8cdb11 100644 --- a/src/test/run-pass/format-nan.rs +++ b/src/test/run-pass/format-nan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { use std::f64; diff --git a/src/test/run-pass/format-ref-cell.rs b/src/test/run-pass/format-ref-cell.rs index ce26fbd4c0..0f16dfa1e8 100644 --- a/src/test/run-pass/format-ref-cell.rs +++ b/src/test/run-pass/format-ref-cell.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::RefCell; diff --git a/src/test/run-pass/fsu-moves-and-copies.rs b/src/test/run-pass/fsu-moves-and-copies.rs index fecaf279d0..dd58787a1d 100644 --- a/src/test/run-pass/fsu-moves-and-copies.rs +++ b/src/test/run-pass/fsu-moves-and-copies.rs @@ -11,7 +11,6 @@ // Issue 4691: Ensure that functional-struct-updates operates // correctly and moves rather than copy when appropriate. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/fun-call-variants.rs b/src/test/run-pass/fun-call-variants.rs index 0fe4bbcb7a..3bb6df33f7 100644 --- a/src/test/run-pass/fun-call-variants.rs +++ b/src/test/run-pass/fun-call-variants.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn ho(f: F) -> isize where F: FnOnce(isize) -> isize { let n: isize = f(3); return n; } diff --git a/src/test/run-pass/fun-indirect-call.rs b/src/test/run-pass/fun-indirect-call.rs index 48dfcb73da..b28c64d06b 100644 --- a/src/test/run-pass/fun-indirect-call.rs +++ b/src/test/run-pass/fun-indirect-call.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 fn f() -> isize { return 42; } diff --git a/src/test/run-pass/func-arg-incomplete-pattern.rs b/src/test/run-pass/func-arg-incomplete-pattern.rs index 2833723708..6030da44e4 100644 --- a/src/test/run-pass/func-arg-incomplete-pattern.rs +++ b/src/test/run-pass/func-arg-incomplete-pattern.rs @@ -11,7 +11,6 @@ // Test that we do not leak when the arg pattern must drop part of the // argument (in this case, the `y` field). -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/func-arg-ref-pattern.rs b/src/test/run-pass/func-arg-ref-pattern.rs index fcc00afb00..ab565e7abc 100644 --- a/src/test/run-pass/func-arg-ref-pattern.rs +++ b/src/test/run-pass/func-arg-ref-pattern.rs @@ -14,7 +14,6 @@ // boxes. Make sure that we don't free the box as we match the // pattern. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/func-arg-wild-pattern.rs b/src/test/run-pass/func-arg-wild-pattern.rs index 4f74ca0ff7..3ab3ee4db2 100644 --- a/src/test/run-pass/func-arg-wild-pattern.rs +++ b/src/test/run-pass/func-arg-wild-pattern.rs @@ -11,7 +11,6 @@ // Test that we can compile code that uses a `_` in function argument // patterns. -// pretty-expanded FIXME #23616 fn foo((x, _): (isize, isize)) -> isize { x diff --git a/src/test/run-pass/generic-exterior-unique.rs b/src/test/run-pass/generic-exterior-unique.rs index 0e3ce3869b..8dbe6de838 100644 --- a/src/test/run-pass/generic-exterior-unique.rs +++ b/src/test/run-pass/generic-exterior-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/generic-extern-mangle.rs b/src/test/run-pass/generic-extern-mangle.rs index 7a765703e2..67aea1f9f8 100644 --- a/src/test/run-pass/generic-extern-mangle.rs +++ b/src/test/run-pass/generic-extern-mangle.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/generic-fn-infer.rs b/src/test/run-pass/generic-fn-infer.rs index e01f507372..181e05183d 100644 --- a/src/test/run-pass/generic-fn-infer.rs +++ b/src/test/run-pass/generic-fn-infer.rs @@ -13,7 +13,6 @@ // Issue #45: infer type parameters in function applications -// pretty-expanded FIXME #23616 fn id(x: T) -> T { return x; } diff --git a/src/test/run-pass/generic-object.rs b/src/test/run-pass/generic-object.rs index 44b32f62f9..0a59a925a5 100644 --- a/src/test/run-pass/generic-object.rs +++ b/src/test/run-pass/generic-object.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/generic-static-methods.rs b/src/test/run-pass/generic-static-methods.rs index 49f8d6a3ad..7a496ebf8c 100644 --- a/src/test/run-pass/generic-static-methods.rs +++ b/src/test/run-pass/generic-static-methods.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait vec_utils { fn map_(x: &Self, f: F) -> Vec where F: FnMut(&T) -> U; diff --git a/src/test/run-pass/generic-type.rs b/src/test/run-pass/generic-type.rs index 73fc3a0d80..8e7a3add34 100644 --- a/src/test/run-pass/generic-type.rs +++ b/src/test/run-pass/generic-type.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 struct Pair {x: T, y: T} diff --git a/src/test/run-pass/generic-unique.rs b/src/test/run-pass/generic-unique.rs index 9cf98364eb..21e9a9a80d 100644 --- a/src/test/run-pass/generic-unique.rs +++ b/src/test/run-pass/generic-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/getopts_ref.rs b/src/test/run-pass/getopts_ref.rs index 52b06ab292..c9595d09e2 100644 --- a/src/test/run-pass/getopts_ref.rs +++ b/src/test/run-pass/getopts_ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/global-scope.rs b/src/test/run-pass/global-scope.rs index 64d9368a88..13da404c25 100644 --- a/src/test/run-pass/global-scope.rs +++ b/src/test/run-pass/global-scope.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn f() -> isize { return 1; } diff --git a/src/test/run-pass/guards-not-exhaustive.rs b/src/test/run-pass/guards-not-exhaustive.rs index f5f8091493..53c3eff5b8 100644 --- a/src/test/run-pass/guards-not-exhaustive.rs +++ b/src/test/run-pass/guards-not-exhaustive.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] enum Q { R(Option) } diff --git a/src/test/run-pass/guards.rs b/src/test/run-pass/guards.rs index 11c67b8af8..d79dbabac2 100644 --- a/src/test/run-pass/guards.rs +++ b/src/test/run-pass/guards.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Pair { x: isize, y: isize } diff --git a/src/test/run-pass/hrtb-fn-like-trait-object.rs b/src/test/run-pass/hrtb-fn-like-trait-object.rs index 858179fb5f..8e2e21bed0 100644 --- a/src/test/run-pass/hrtb-fn-like-trait-object.rs +++ b/src/test/run-pass/hrtb-fn-like-trait-object.rs @@ -10,7 +10,6 @@ // A basic test of using a higher-ranked trait bound. -// pretty-expanded FIXME #23616 trait FnLike { fn call(&self, arg: A) -> R; diff --git a/src/test/run-pass/hrtb-fn-like-trait.rs b/src/test/run-pass/hrtb-fn-like-trait.rs index 8b4c2aec84..71e314b513 100644 --- a/src/test/run-pass/hrtb-fn-like-trait.rs +++ b/src/test/run-pass/hrtb-fn-like-trait.rs @@ -10,7 +10,6 @@ // A basic test of using a higher-ranked trait bound. -// pretty-expanded FIXME #23616 trait FnLike { fn call(&self, arg: A) -> R; diff --git a/src/test/run-pass/hrtb-trait-object-paren-notation.rs b/src/test/run-pass/hrtb-trait-object-paren-notation.rs index 7741f1904f..fefbd00476 100644 --- a/src/test/run-pass/hrtb-trait-object-paren-notation.rs +++ b/src/test/run-pass/hrtb-trait-object-paren-notation.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/huge-largest-array.rs b/src/test/run-pass/huge-largest-array.rs index 2345bb01d8..f0bb31b847 100644 --- a/src/test/run-pass/huge-largest-array.rs +++ b/src/test/run-pass/huge-largest-array.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/hygiene-dodging-1.rs b/src/test/run-pass/hygiene-dodging-1.rs index e5acc4a2ed..83f09850f7 100644 --- a/src/test/run-pass/hygiene-dodging-1.rs +++ b/src/test/run-pass/hygiene-dodging-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod x { pub fn g() -> usize {14} diff --git a/src/test/run-pass/hygienic-labels-in-let.rs b/src/test/run-pass/hygienic-labels-in-let.rs index 589d6e1581..5b45f1e0d3 100644 --- a/src/test/run-pass/hygienic-labels-in-let.rs +++ b/src/test/run-pass/hygienic-labels-in-let.rs @@ -10,6 +10,14 @@ // ignore-pretty: pprust doesn't print hygiene output +// Test that labels injected by macros do not break hygiene. This +// checks cases where the macros invocations are under the rhs of a +// let statement. + +// Issue #24278: The label/lifetime shadowing checker from #24162 +// conservatively ignores hygiene, and thus issues warnings that are +// both true- and false-positives for this test. + macro_rules! loop_x { ($e: expr) => { // $e shouldn't be able to interact with this 'x diff --git a/src/test/run-pass/hygienic-labels.rs b/src/test/run-pass/hygienic-labels.rs index 2d530275ea..a5882f0229 100644 --- a/src/test/run-pass/hygienic-labels.rs +++ b/src/test/run-pass/hygienic-labels.rs @@ -8,7 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// Test that labels injected by macros do not break hygiene. + +// Issue #24278: The label/lifetime shadowing checker from #24162 +// conservatively ignores hygiene, and thus issues warnings that are +// both true- and false-positives for this test. macro_rules! loop_x { ($e: expr) => { diff --git a/src/test/run-pass/i32-sub.rs b/src/test/run-pass/i32-sub.rs index 2cc4e880bb..075faba2fc 100644 --- a/src/test/run-pass/i32-sub.rs +++ b/src/test/run-pass/i32-sub.rs @@ -11,6 +11,5 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: i32 = -400; x = 0 - x; assert!((x == 400)); } diff --git a/src/test/run-pass/i8-incr.rs b/src/test/run-pass/i8-incr.rs index 5dd53a268b..242cea264a 100644 --- a/src/test/run-pass/i8-incr.rs +++ b/src/test/run-pass/i8-incr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: i8 = -12; diff --git a/src/test/run-pass/if-let.rs b/src/test/run-pass/if-let.rs index c41d02f9b3..13134abd8f 100644 --- a/src/test/run-pass/if-let.rs +++ b/src/test/run-pass/if-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = Some(3); diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 41c859214e..ea9db9b1e1 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.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. // @@ -72,6 +72,13 @@ pub fn main() { t!(format!("{:X}", 10_usize), "A"); t!(format!("{}", "foo"), "foo"); t!(format!("{}", "foo".to_string()), "foo"); + if cfg!(target_pointer_width = "32") { + t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); + } else { + t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); + } t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); t!(format!("{:x}", A), "aloha"); @@ -85,9 +92,8 @@ pub fn main() { t!(format!("{}", 5 + 5), "10"); t!(format!("{:#4}", C), "☃123"); - // FIXME(#20676) - // let a: &fmt::Debug = &1; - // t!(format!("{:?}", a), "1"); + let a: &fmt::Debug = &1; + t!(format!("{:?}", a), "1"); // Formatting strings and their arguments @@ -138,6 +144,12 @@ pub fn main() { t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + // Float edge cases + t!(format!("{}", -0.0), "0"); + t!(format!("{:?}", -0.0), "-0"); + t!(format!("{:?}", 0.0), "0"); + + // Test that pointers don't get truncated. { let val = usize::MAX; diff --git a/src/test/run-pass/impl-inherent-non-conflict.rs b/src/test/run-pass/impl-inherent-non-conflict.rs index 210bc34bcd..0d43f1ca70 100644 --- a/src/test/run-pass/impl-inherent-non-conflict.rs +++ b/src/test/run-pass/impl-inherent-non-conflict.rs @@ -12,7 +12,6 @@ // with the same name, which can be called on values that have a // precise enough type to allow distinguishing between the methods. -// pretty-expanded FIXME #23616 struct Foo(T); diff --git a/src/test/run-pass/impl-inherent-prefer-over-trait.rs b/src/test/run-pass/impl-inherent-prefer-over-trait.rs index 26f12e9730..f0195976aa 100644 --- a/src/test/run-pass/impl-inherent-prefer-over-trait.rs +++ b/src/test/run-pass/impl-inherent-prefer-over-trait.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/impl-not-adjacent-to-type.rs b/src/test/run-pass/impl-not-adjacent-to-type.rs index 2ba7375d67..beba056b72 100644 --- a/src/test/run-pass/impl-not-adjacent-to-type.rs +++ b/src/test/run-pass/impl-not-adjacent-to-type.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub struct Point { diff --git a/src/test/run-pass/import-glob-crate.rs b/src/test/run-pass/import-glob-crate.rs index eb9ec6fe98..b2a9b08b01 100644 --- a/src/test/run-pass/import-glob-crate.rs +++ b/src/test/run-pass/import-glob-crate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/inferred-suffix-in-pattern-range.rs b/src/test/run-pass/inferred-suffix-in-pattern-range.rs index fcbd4b3323..22369c77ed 100644 --- a/src/test/run-pass/inferred-suffix-in-pattern-range.rs +++ b/src/test/run-pass/inferred-suffix-in-pattern-range.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 2; diff --git a/src/test/run-pass/inherent-trait-method-order.rs b/src/test/run-pass/inherent-trait-method-order.rs index 042268435c..5489a61f7d 100644 --- a/src/test/run-pass/inherent-trait-method-order.rs +++ b/src/test/run-pass/inherent-trait-method-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/init-large-type.rs b/src/test/run-pass/init-large-type.rs index 26d58d34b9..dafa8ee103 100644 --- a/src/test/run-pass/init-large-type.rs +++ b/src/test/run-pass/init-large-type.rs @@ -26,7 +26,7 @@ const SIZE: usize = 1024 * 1024; fn main() { // do the test in a new thread to avoid (spurious?) stack overflows - let _ = thread::scoped(|| { + thread::spawn(|| { let _memory: [u8; SIZE] = unsafe { init() }; }).join(); } diff --git a/src/test/run-pass/init-res-into-things.rs b/src/test/run-pass/init-res-into-things.rs index eb50fbed77..97b32189d0 100644 --- a/src/test/run-pass/init-res-into-things.rs +++ b/src/test/run-pass/init-res-into-things.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/inner-attrs-on-impl.rs b/src/test/run-pass/inner-attrs-on-impl.rs index a807e582ff..d8d9d5136e 100644 --- a/src/test/run-pass/inner-attrs-on-impl.rs +++ b/src/test/run-pass/inner-attrs-on-impl.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo; diff --git a/src/test/run-pass/inner-static.rs b/src/test/run-pass/inner-static.rs index 48f2006ed5..b93ca943e4 100644 --- a/src/test/run-pass/inner-static.rs +++ b/src/test/run-pass/inner-static.rs @@ -10,7 +10,6 @@ // aux-build:inner_static.rs -// pretty-expanded FIXME #23616 extern crate inner_static; diff --git a/src/test/run-pass/integer-literal-radix.rs b/src/test/run-pass/integer-literal-radix.rs index b782925fa9..ba9d22f06a 100644 --- a/src/test/run-pass/integer-literal-radix.rs +++ b/src/test/run-pass/integer-literal-radix.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let a = 0xBEEF_isize; diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index 44dd191eb3..fa97ef8fcd 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics, main)] diff --git a/src/test/run-pass/intrinsic-assume.rs b/src/test/run-pass/intrinsic-assume.rs index fc886d7e30..ff7d799f64 100644 --- a/src/test/run-pass/intrinsic-assume.rs +++ b/src/test/run-pass/intrinsic-assume.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/intrinsic-atomics-cc.rs b/src/test/run-pass/intrinsic-atomics-cc.rs index c5fe02b919..abb85cc7f1 100644 --- a/src/test/run-pass/intrinsic-atomics-cc.rs +++ b/src/test/run-pass/intrinsic-atomics-cc.rs @@ -10,7 +10,6 @@ // aux-build:cci_intrinsic.rs -// pretty-expanded FIXME #23616 extern crate cci_intrinsic; use cci_intrinsic::atomic_xchg; diff --git a/src/test/run-pass/intrinsic-atomics.rs b/src/test/run-pass/intrinsic-atomics.rs index 61a9f6109a..4ccab55e94 100644 --- a/src/test/run-pass/intrinsic-atomics.rs +++ b/src/test/run-pass/intrinsic-atomics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/intrinsic-move-val.rs b/src/test/run-pass/intrinsic-move-val.rs index 98f069f77f..2e75f2dccd 100644 --- a/src/test/run-pass/intrinsic-move-val.rs +++ b/src/test/run-pass/intrinsic-move-val.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/intrinsic-return-address.rs b/src/test/run-pass/intrinsic-return-address.rs index 1ff910356e..63aed3f009 100644 --- a/src/test/run-pass/intrinsic-return-address.rs +++ b/src/test/run-pass/intrinsic-return-address.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics)] diff --git a/src/test/run-pass/intrinsic-unreachable.rs b/src/test/run-pass/intrinsic-unreachable.rs index 86a370a094..a86fc110ae 100644 --- a/src/test/run-pass/intrinsic-unreachable.rs +++ b/src/test/run-pass/intrinsic-unreachable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 15dbe796ef..f1d731c8b1 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(negate_unsigned)] #![feature(intrinsics)] diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index 841ff297a2..37ceaae373 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(intrinsics, core)] macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ - use std::num::Float; let (a, b) = (&$a, &$b); assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); diff --git a/src/test/run-pass/issue-10392.rs b/src/test/run-pass/issue-10392.rs index 2d695c75d3..1a5f423b0f 100644 --- a/src/test/run-pass/issue-10392.rs +++ b/src/test/run-pass/issue-10392.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A { foo: isize } struct B { a: isize, b: isize, c: isize } diff --git a/src/test/run-pass/issue-10626.rs b/src/test/run-pass/issue-10626.rs index 2c0811b69e..0d8f222548 100644 --- a/src/test/run-pass/issue-10626.rs +++ b/src/test/run-pass/issue-10626.rs @@ -15,7 +15,7 @@ #![feature(old_io)] use std::env; -use std::old_io::process; +use std::process::{Command, Stdio}; pub fn main () { let args: Vec = env::args().collect(); @@ -29,7 +29,7 @@ pub fn main () { return; } - let mut p = process::Command::new(&args[0]); - p.arg("child").stdout(process::Ignored).stderr(process::Ignored); + let mut p = Command::new(&args[0]); + p.arg("child").stdout(Stdio::null()).stderr(Stdio::null()); println!("{:?}", p.spawn().unwrap().wait()); } diff --git a/src/test/run-pass/issue-10734.rs b/src/test/run-pass/issue-10734.rs index 49694f2755..c99cad85cc 100644 --- a/src/test/run-pass/issue-10734.rs +++ b/src/test/run-pass/issue-10734.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/issue-10802.rs b/src/test/run-pass/issue-10802.rs index bb32263509..2256315a37 100644 --- a/src/test/run-pass/issue-10802.rs +++ b/src/test/run-pass/issue-10802.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-1112.rs b/src/test/run-pass/issue-1112.rs index 3d131b5103..72d1a43e88 100644 --- a/src/test/run-pass/issue-1112.rs +++ b/src/test/run-pass/issue-1112.rs @@ -11,7 +11,6 @@ // Issue #1112 // Alignment of interior pointers to dynamic-size types -// pretty-expanded FIXME #23616 struct X { a: T, diff --git a/src/test/run-pass/issue-11552.rs b/src/test/run-pass/issue-11552.rs index 1f91c6aaa4..5193330a45 100644 --- a/src/test/run-pass/issue-11552.rs +++ b/src/test/run-pass/issue-11552.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/issue-11577.rs b/src/test/run-pass/issue-11577.rs index ecb7a3a369..81588e8ef7 100644 --- a/src/test/run-pass/issue-11577.rs +++ b/src/test/run-pass/issue-11577.rs @@ -1,4 +1,3 @@ -// pretty-expanded FIXME #23616 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at diff --git a/src/test/run-pass/issue-11677.rs b/src/test/run-pass/issue-11677.rs index a3eec42831..d4244d4443 100644 --- a/src/test/run-pass/issue-11677.rs +++ b/src/test/run-pass/issue-11677.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_code)] diff --git a/src/test/run-pass/issue-11736.rs b/src/test/run-pass/issue-11736.rs index fde04efc8b..b4621a2d05 100644 --- a/src/test/run-pass/issue-11736.rs +++ b/src/test/run-pass/issue-11736.rs @@ -12,10 +12,7 @@ #![feature(collections)] -extern crate collections; - use std::collections::BitVec; -use std::num::Float; fn main() { // Generate sieve of Eratosthenes for n up to 1e6 diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 35c25b33a9..483ae02d2d 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private, old_io)] diff --git a/src/test/run-pass/issue-11940.rs b/src/test/run-pass/issue-11940.rs index 8732def0a1..186446a345 100644 --- a/src/test/run-pass/issue-11940.rs +++ b/src/test/run-pass/issue-11940.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const TEST_STR: &'static str = "abcd"; diff --git a/src/test/run-pass/issue-12285.rs b/src/test/run-pass/issue-12285.rs index 3a5b7e8692..fb98909eb9 100644 --- a/src/test/run-pass/issue-12285.rs +++ b/src/test/run-pass/issue-12285.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S; diff --git a/src/test/run-pass/issue-12677.rs b/src/test/run-pass/issue-12677.rs index 493bdb30e3..e83a2e9727 100644 --- a/src/test/run-pass/issue-12677.rs +++ b/src/test/run-pass/issue-12677.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let s = "Hello"; diff --git a/src/test/run-pass/issue-12684.rs b/src/test/run-pass/issue-12684.rs deleted file mode 100644 index 2b89915516..0000000000 --- a/src/test/run-pass/issue-12684.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013-2014 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. - -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - -use std::time::Duration; -use std::thread; - -fn main() { - thread::spawn(move|| customtask()).join().ok().unwrap(); -} - -fn customtask() { - let mut timer = std::old_io::timer::Timer::new().unwrap(); - let periodic = timer.periodic(Duration::milliseconds(10)); - periodic.recv(); -} diff --git a/src/test/run-pass/issue-12699.rs b/src/test/run-pass/issue-12699.rs index ac5a9b728b..1e9f30bb76 100644 --- a/src/test/run-pass/issue-12699.rs +++ b/src/test/run-pass/issue-12699.rs @@ -8,13 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - -use std::old_io::timer; -use std::time::Duration; +use std::thread; fn main() { - timer::sleep(Duration::milliseconds(250)); + thread::sleep_ms(250); } diff --git a/src/test/run-pass/issue-12860.rs b/src/test/run-pass/issue-12860.rs index dddfb9bacf..c854747bcf 100644 --- a/src/test/run-pass/issue-12860.rs +++ b/src/test/run-pass/issue-12860.rs @@ -30,7 +30,7 @@ fn main() { let middle = XYZ{x: 0, y: 0, z: 0}; border.insert(middle); - while border.len() > 0 && connected.len() < 10000 { + while !border.is_empty() && connected.len() < 10000 { let choice = *(border.iter().next().unwrap()); border.remove(&choice); connected.insert(choice); diff --git a/src/test/run-pass/issue-13105.rs b/src/test/run-pass/issue-13105.rs index 14de9e9030..ca68272d2d 100644 --- a/src/test/run-pass/issue-13105.rs +++ b/src/test/run-pass/issue-13105.rs @@ -10,11 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::marker::MarkerTrait; - -trait Foo : MarkerTrait { +trait Foo { fn quux(u8) {} } diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs index ec9d777974..36f606e5d7 100644 --- a/src/test/run-pass/issue-13204.rs +++ b/src/test/run-pass/issue-13204.rs @@ -11,7 +11,6 @@ // Test that when instantiating trait default methods, typeck handles // lifetime parameters defined on the method bound correctly. -// pretty-expanded FIXME #23616 pub trait Foo { fn bar<'a, I: Iterator>(&self, it: I) -> usize { diff --git a/src/test/run-pass/issue-13259-windows-tcb-trash.rs b/src/test/run-pass/issue-13259-windows-tcb-trash.rs index 34960b2645..9ebbddf514 100644 --- a/src/test/run-pass/issue-13259-windows-tcb-trash.rs +++ b/src/test/run-pass/issue-13259-windows-tcb-trash.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(libc)] +#![feature(libc, std_misc)] extern crate libc; diff --git a/src/test/run-pass/issue-13323.rs b/src/test/run-pass/issue-13323.rs index 90d16aaf14..68c6ce7a7b 100644 --- a/src/test/run-pass/issue-13323.rs +++ b/src/test/run-pass/issue-13323.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-13494.rs b/src/test/run-pass/issue-13494.rs index d1b1647de7..71897ea68c 100644 --- a/src/test/run-pass/issue-13494.rs +++ b/src/test/run-pass/issue-13494.rs @@ -26,7 +26,7 @@ fn helper(rx: Receiver>) { fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { helper(rx) }); + let t = thread::spawn(move|| { helper(rx) }); let (snd, rcv) = channel::(); for _ in 1..100000 { snd.send(1).unwrap(); @@ -38,4 +38,5 @@ fn main() { } } drop(tx); + t.join(); } diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 0b35ccf26f..91ec3e8540 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -10,7 +10,6 @@ // aux-build:issue13507.rs -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-13763.rs b/src/test/run-pass/issue-13763.rs index fb82cccc87..e11270c94c 100644 --- a/src/test/run-pass/issue-13763.rs +++ b/src/test/run-pass/issue-13763.rs @@ -14,7 +14,7 @@ use std::u8; -const NUM: usize = u8::BITS as usize; +const NUM: usize = u8::BITS; struct MyStruct { nums: [usize; 8] } diff --git a/src/test/run-pass/issue-13867.rs b/src/test/run-pass/issue-13867.rs index a902e141bb..e21070e2ea 100644 --- a/src/test/run-pass/issue-13867.rs +++ b/src/test/run-pass/issue-13867.rs @@ -11,7 +11,6 @@ // Test that codegen works correctly when there are multiple refutable // patterns in match expression. -// pretty-expanded FIXME #23616 enum Foo { FooUint(usize), diff --git a/src/test/run-pass/issue-14308.rs b/src/test/run-pass/issue-14308.rs index f67d0946e9..a61cb18faa 100644 --- a/src/test/run-pass/issue-14308.rs +++ b/src/test/run-pass/issue-14308.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A(isize); struct B; diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs index ab9633ca1f..7e24c8f73a 100644 --- a/src/test/run-pass/issue-14456.rs +++ b/src/test/run-pass/issue-14456.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(io, process_capture)] diff --git a/src/test/run-pass/issue-14865.rs b/src/test/run-pass/issue-14865.rs index e78736b77f..1ec268bb17 100644 --- a/src/test/run-pass/issue-14865.rs +++ b/src/test/run-pass/issue-14865.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum X { Foo(usize), diff --git a/src/test/run-pass/issue-14901.rs b/src/test/run-pass/issue-14901.rs index 7e7886e3a6..5668367846 100644 --- a/src/test/run-pass/issue-14901.rs +++ b/src/test/run-pass/issue-14901.rs @@ -8,11 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io)] - -use std::old_io::Reader; +pub trait Reader {} enum Wrapper<'a> { WrapReader(&'a (Reader + 'a)) diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 2361c385b4..5f8e7cb814 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(asm)] diff --git a/src/test/run-pass/issue-14940.rs b/src/test/run-pass/issue-14940.rs index a530384d36..b51afc1d02 100644 --- a/src/test/run-pass/issue-14940.rs +++ b/src/test/run-pass/issue-14940.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(old_io, io)] diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index 4369dc6292..ecb83cca6f 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-15104.rs b/src/test/run-pass/issue-15104.rs index db04e10cfe..b55754ee59 100644 --- a/src/test/run-pass/issue-15104.rs +++ b/src/test/run-pass/issue-15104.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-15129.rs b/src/test/run-pass/issue-15129.rs index 54705c6bf1..9bcfa6ea40 100644 --- a/src/test/run-pass/issue-15129.rs +++ b/src/test/run-pass/issue-15129.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub enum T { T1(()), diff --git a/src/test/run-pass/issue-15523-big.rs b/src/test/run-pass/issue-15523-big.rs new file mode 100644 index 0000000000..33c81cab38 --- /dev/null +++ b/src/test/run-pass/issue-15523-big.rs @@ -0,0 +1,48 @@ +// 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. + +// Issue 15523: derive(PartialOrd) should use the provided +// discriminant values for the derived ordering. +// +// This test is checking corner cases that arise when you have +// 64-bit values in the variants. + +#[derive(PartialEq, PartialOrd)] +#[repr(u64)] +enum Eu64 { + Pos2 = 2, + PosMax = !0, + Pos1 = 1, +} + +#[derive(PartialEq, PartialOrd)] +#[repr(i64)] +enum Ei64 { + Pos2 = 2, + Neg1 = -1, + NegMin = 1 << 63, + PosMax = !(1 << 63), + Pos1 = 1, +} + +fn main() { + assert!(Eu64::Pos2 > Eu64::Pos1); + assert!(Eu64::Pos2 < Eu64::PosMax); + assert!(Eu64::Pos1 < Eu64::PosMax); + + + assert!(Ei64::Pos2 > Ei64::Pos1); + assert!(Ei64::Pos2 > Ei64::Neg1); + assert!(Ei64::Pos1 > Ei64::Neg1); + assert!(Ei64::Pos2 > Ei64::NegMin); + assert!(Ei64::Pos1 > Ei64::NegMin); + assert!(Ei64::Pos2 < Ei64::PosMax); + assert!(Ei64::Pos1 < Ei64::PosMax); +} diff --git a/src/test/run-pass/issue-15523.rs b/src/test/run-pass/issue-15523.rs new file mode 100644 index 0000000000..bb8fa6791a --- /dev/null +++ b/src/test/run-pass/issue-15523.rs @@ -0,0 +1,51 @@ +// 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. + +// Issue 15523: derive(PartialOrd) should use the provided +// discriminant values for the derived ordering. +// +// This is checking the basic functionality. + +#[derive(PartialEq, PartialOrd)] +enum E1 { + Pos2 = 2, + Neg1 = -1, + Pos1 = 1, +} + +#[derive(PartialEq, PartialOrd)] +#[repr(u8)] +enum E2 { + Pos2 = 2, + PosMax = !0 as u8, + Pos1 = 1, +} + +#[derive(PartialEq, PartialOrd)] +#[repr(i8)] +enum E3 { + Pos2 = 2, + Neg1 = -1_i8, + Pos1 = 1, +} + +fn main() { + assert!(E1::Pos2 > E1::Pos1); + assert!(E1::Pos1 > E1::Neg1); + assert!(E1::Pos2 > E1::Neg1); + + assert!(E2::Pos2 > E2::Pos1); + assert!(E2::Pos1 < E2::PosMax); + assert!(E2::Pos2 < E2::PosMax); + + assert!(E3::Pos2 > E3::Pos1); + assert!(E3::Pos1 > E3::Neg1); + assert!(E3::Pos2 > E3::Neg1); +} diff --git a/src/test/run-pass/issue-15562.rs b/src/test/run-pass/issue-15562.rs index f1ef57e44b..da1e15d826 100644 --- a/src/test/run-pass/issue-15562.rs +++ b/src/test/run-pass/issue-15562.rs @@ -15,9 +15,6 @@ extern crate issue_15562 as i; pub fn main() { - extern { - fn transmute(); - } unsafe { transmute(); i::transmute(); diff --git a/src/test/run-pass/issue-15673.rs b/src/test/run-pass/issue-15673.rs index 6c76f1595d..c478ca0411 100644 --- a/src/test/run-pass/issue-15673.rs +++ b/src/test/run-pass/issue-15673.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] -use std::iter::AdditiveIterator; fn main() { let x: [u64; 3] = [1, 2, 3]; - assert_eq!(6, (0..3).map(|i| x[i]).sum()); + assert_eq!(6, (0..3).map(|i| x[i]).sum::()); } diff --git a/src/test/run-pass/issue-15689-1.rs b/src/test/run-pass/issue-15689-1.rs index 9fc1cce56b..e3c16793c1 100644 --- a/src/test/run-pass/issue-15689-1.rs +++ b/src/test/run-pass/issue-15689-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] enum Test<'a> { diff --git a/src/test/run-pass/issue-15734.rs b/src/test/run-pass/issue-15734.rs index 67ce6a1c44..7f44c5a84c 100644 --- a/src/test/run-pass/issue-15734.rs +++ b/src/test/run-pass/issue-15734.rs @@ -11,7 +11,6 @@ // If `Index` used an associated type for its output, this test would // work more smoothly. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-15763.rs b/src/test/run-pass/issue-15763.rs index b5251d63ff..0baaaac267 100644 --- a/src/test/run-pass/issue-15763.rs +++ b/src/test/run-pass/issue-15763.rs @@ -87,12 +87,12 @@ fn main() { assert_eq!(cc().unwrap(), 3); assert_eq!(dd().unwrap(), 3); - let i = box 32is as Box; + let i = box 32isize as Box; assert_eq!(i.aaa(), 3); - let i = box 32is as Box; + let i = box 32isize as Box; assert_eq!(i.bbb(), 3); - let i = box 32is as Box; + let i = box 32isize as Box; assert_eq!(i.ccc().unwrap(), 3); - let i = box 32is as Box; + let i = box 32isize as Box; assert_eq!(i.ddd().unwrap(), 3); } diff --git a/src/test/run-pass/issue-15793.rs b/src/test/run-pass/issue-15793.rs index 21baf47ee6..432174a1f5 100644 --- a/src/test/run-pass/issue-15793.rs +++ b/src/test/run-pass/issue-15793.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum NestedEnum { First, diff --git a/src/test/run-pass/issue-15858.rs b/src/test/run-pass/issue-15858.rs index 265db3fe13..4f084d7891 100644 --- a/src/test/run-pass/issue-15858.rs +++ b/src/test/run-pass/issue-15858.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs b/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs index 6b75e4e479..2ec97e373b 100644 --- a/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs +++ b/src/test/run-pass/issue-15881-model-lexer-dotdotdot.rs @@ -10,7 +10,6 @@ // // regression test for the model lexer handling the DOTDOTDOT syntax (#15877) -// pretty-expanded FIXME #23616 pub fn main() { match 5_usize { diff --git a/src/test/run-pass/issue-16151.rs b/src/test/run-pass/issue-16151.rs index 242bcb69be..212dfaf3cb 100644 --- a/src/test/run-pass/issue-16151.rs +++ b/src/test/run-pass/issue-16151.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/issue-16530.rs b/src/test/run-pass/issue-16530.rs index bf33221431..77ec44161e 100644 --- a/src/test/run-pass/issue-16530.rs +++ b/src/test/run-pass/issue-16530.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(hash)] diff --git a/src/test/run-pass/issue-16560.rs b/src/test/run-pass/issue-16560.rs index 33842fab69..a9f7d86f95 100644 --- a/src/test/run-pass/issue-16560.rs +++ b/src/test/run-pass/issue-16560.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/issue-16596.rs b/src/test/run-pass/issue-16596.rs index 743dbbc9b9..d70158743e 100644 --- a/src/test/run-pass/issue-16596.rs +++ b/src/test/run-pass/issue-16596.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait MatrixRow { fn dummy(&self) { }} diff --git a/src/test/run-pass/issue-16602-1.rs b/src/test/run-pass/issue-16602-1.rs new file mode 100644 index 0000000000..ee638edad6 --- /dev/null +++ b/src/test/run-pass/issue-16602-1.rs @@ -0,0 +1,15 @@ +// 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. + +fn main() { + let mut t = [1; 2]; + t = [t[1] * 2, t[0] * 2]; + assert_eq!(&t[..], &[2, 2]); +} diff --git a/src/test/run-pass/issue-16602-2.rs b/src/test/run-pass/issue-16602-2.rs new file mode 100644 index 0000000000..742eb6c280 --- /dev/null +++ b/src/test/run-pass/issue-16602-2.rs @@ -0,0 +1,21 @@ +// 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. + +struct A { + pub x: u32, + pub y: u32, +} + +fn main() { + let mut a = A { x: 1, y: 1 }; + a = A { x: a.y * 2, y: a.x * 2 }; + assert_eq!(a.x, 2); + assert_eq!(a.y, 2); +} diff --git a/src/test/run-pass/issue-16602-3.rs b/src/test/run-pass/issue-16602-3.rs new file mode 100644 index 0000000000..d29932dcf6 --- /dev/null +++ b/src/test/run-pass/issue-16602-3.rs @@ -0,0 +1,34 @@ +// 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. + +#[derive(Debug)] +enum Foo { + Bar(u32, u32), + Baz(&'static u32, &'static u32) +} + +static NUM: u32 = 100; + +fn main () { + let mut b = Foo::Baz(&NUM, &NUM); + b = Foo::Bar(f(&b), g(&b)); +} + +static FNUM: u32 = 1; + +fn f (b: &Foo) -> u32 { + FNUM +} + +static GNUM: u32 = 2; + +fn g (b: &Foo) -> u32 { + GNUM +} diff --git a/src/test/run-pass/issue-16648.rs b/src/test/run-pass/issue-16648.rs index f0ff9ce755..384bd9df7c 100644 --- a/src/test/run-pass/issue-16648.rs +++ b/src/test/run-pass/issue-16648.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-16739.rs b/src/test/run-pass/issue-16739.rs index 99ddaba4e5..f8cffdd38c 100644 --- a/src/test/run-pass/issue-16739.rs +++ b/src/test/run-pass/issue-16739.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-16774.rs b/src/test/run-pass/issue-16774.rs index 17d0969ce1..627717ab1c 100644 --- a/src/test/run-pass/issue-16774.rs +++ b/src/test/run-pass/issue-16774.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-1701.rs b/src/test/run-pass/issue-1701.rs index b8c51f2cd3..3a2e46c62b 100644 --- a/src/test/run-pass/issue-1701.rs +++ b/src/test/run-pass/issue-1701.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum pattern { tabby, tortoiseshell, calico } enum breed { beagle, rottweiler, pug } diff --git a/src/test/run-pass/issue-17068.rs b/src/test/run-pass/issue-17068.rs index 55a6d4cdba..91264b4ac3 100644 --- a/src/test/run-pass/issue-17068.rs +++ b/src/test/run-pass/issue-17068.rs @@ -10,7 +10,6 @@ // Test that regionck creates the right region links in the pattern // binding of a for loop -// pretty-expanded FIXME #23616 fn foo<'a>(v: &'a [usize]) -> &'a usize { for &ref x in v { return x; } diff --git a/src/test/run-pass/issue-17074.rs b/src/test/run-pass/issue-17074.rs index 08c313ab0a..ec2d8f7978 100644 --- a/src/test/run-pass/issue-17074.rs +++ b/src/test/run-pass/issue-17074.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static X2: u64 = !0 as u16 as u64; static Y2: u64 = !0 as u32 as u64; diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs index f17834e8d3..6a8f7d992a 100644 --- a/src/test/run-pass/issue-17216.rs +++ b/src/test/run-pass/issue-17216.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-17233.rs b/src/test/run-pass/issue-17233.rs index 756822d4f4..e9f0c73e29 100644 --- a/src/test/run-pass/issue-17233.rs +++ b/src/test/run-pass/issue-17233.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const X1: &'static [u8] = &[b'1']; const X2: &'static [u8] = b"1"; diff --git a/src/test/run-pass/issue-17302.rs b/src/test/run-pass/issue-17302.rs index 35bd07c896..5962558116 100644 --- a/src/test/run-pass/issue-17302.rs +++ b/src/test/run-pass/issue-17302.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static mut DROPPED: [bool; 2] = [false, false]; diff --git a/src/test/run-pass/issue-17662.rs b/src/test/run-pass/issue-17662.rs index 36e12b96c8..320d108cfa 100644 --- a/src/test/run-pass/issue-17662.rs +++ b/src/test/run-pass/issue-17662.rs @@ -10,7 +10,6 @@ // aux-build:issue-17662.rs -// pretty-expanded FIXME #23616 extern crate issue_17662 as i; diff --git a/src/test/run-pass/issue-17718-parse-const.rs b/src/test/run-pass/issue-17718-parse-const.rs index 1fc8f3274d..9be92d6597 100644 --- a/src/test/run-pass/issue-17718-parse-const.rs +++ b/src/test/run-pass/issue-17718-parse-const.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const FOO: usize = 3; diff --git a/src/test/run-pass/issue-17718.rs b/src/test/run-pass/issue-17718.rs index 13e082eada..2b84ce71dd 100644 --- a/src/test/run-pass/issue-17718.rs +++ b/src/test/run-pass/issue-17718.rs @@ -10,7 +10,6 @@ // aux-build:issue-17718.rs -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-17734.rs b/src/test/run-pass/issue-17734.rs index 3cf9c62b40..0fc8eea778 100644 --- a/src/test/run-pass/issue-17734.rs +++ b/src/test/run-pass/issue-17734.rs @@ -10,7 +10,6 @@ // Test that generating drop glue for Box doesn't ICE -// pretty-expanded FIXME #23616 fn f(s: Box) -> Box { s diff --git a/src/test/run-pass/issue-17877.rs b/src/test/run-pass/issue-17877.rs index 41fab9d9d5..6c87e8d35f 100644 --- a/src/test/run-pass/issue-17877.rs +++ b/src/test/run-pass/issue-17877.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-18352.rs b/src/test/run-pass/issue-18352.rs index 4e60a7d9b5..cce6ba407a 100644 --- a/src/test/run-pass/issue-18352.rs +++ b/src/test/run-pass/issue-18352.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const X: &'static str = "12345"; diff --git a/src/test/run-pass/issue-18412.rs b/src/test/run-pass/issue-18412.rs index 41dacd3320..1017fab5ae 100644 --- a/src/test/run-pass/issue-18412.rs +++ b/src/test/run-pass/issue-18412.rs @@ -11,7 +11,6 @@ // Test that non-static methods can be assigned to local variables as // function pointers. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> usize; diff --git a/src/test/run-pass/issue-18652.rs b/src/test/run-pass/issue-18652.rs index a3affb7bf8..8ab645e54a 100644 --- a/src/test/run-pass/issue-18652.rs +++ b/src/test/run-pass/issue-18652.rs @@ -12,7 +12,6 @@ // once closure as an optimization by trans. This used to hit an // incorrect assert. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/issue-18738.rs b/src/test/run-pass/issue-18738.rs index a92fcb01f5..819ec532ed 100644 --- a/src/test/run-pass/issue-18738.rs +++ b/src/test/run-pass/issue-18738.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #[derive(Eq, PartialEq, PartialOrd, Ord)] enum Test<'a> { Int(&'a isize), diff --git a/src/test/run-pass/issue-18767.rs b/src/test/run-pass/issue-18767.rs index 8e51a900c0..264985b791 100644 --- a/src/test/run-pass/issue-18767.rs +++ b/src/test/run-pass/issue-18767.rs @@ -11,7 +11,6 @@ // Test that regionck uses the right memcat for patterns in for loops // and doesn't ICE. -// pretty-expanded FIXME #23616 fn main() { for &&x in Some(&0_usize).iter() { diff --git a/src/test/run-pass/issue-18859.rs b/src/test/run-pass/issue-18859.rs index 16e6c99f0e..7c7501d342 100644 --- a/src/test/run-pass/issue-18859.rs +++ b/src/test/run-pass/issue-18859.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod foo { pub mod bar { diff --git a/src/test/run-pass/issue-18619.rs b/src/test/run-pass/issue-19097.rs similarity index 74% rename from src/test/run-pass/issue-18619.rs rename to src/test/run-pass/issue-19097.rs index a256e61921..ca4b72f9e5 100644 --- a/src/test/run-pass/issue-18619.rs +++ b/src/test/run-pass/issue-19097.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +// regression test for #19097 -#![feature(old_io)] +struct Foo(T); -use std::old_io::FileType; - -pub fn main() { - let _ = FileType::RegularFile.clone(); +impl<'a, T> Foo<&'a T> { + fn foo(&self) {} +} +impl<'a, T> Foo<&'a mut T> { + fn foo(&self) {} } + +fn main() {} diff --git a/src/test/run-pass/issue-19244.rs b/src/test/run-pass/issue-19244.rs index f25450a891..92ac2e37b9 100644 --- a/src/test/run-pass/issue-19244.rs +++ b/src/test/run-pass/issue-19244.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct MyStruct { field: usize } struct Nested { nested: MyStruct } diff --git a/src/test/run-pass/issue-19811-escape-unicode.rs b/src/test/run-pass/issue-19811-escape-unicode.rs index 5b415c6388..e6e9bf6e63 100644 --- a/src/test/run-pass/issue-19811-escape-unicode.rs +++ b/src/test/run-pass/issue-19811-escape-unicode.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/issue-20454.rs b/src/test/run-pass/issue-20454.rs index d527d9519c..522f544a21 100644 --- a/src/test/run-pass/issue-20454.rs +++ b/src/test/run-pass/issue-20454.rs @@ -13,11 +13,11 @@ use std::thread; fn _foo() { - let _t = thread::scoped(move || { // no need for -> () + thread::spawn(move || { // no need for -> () loop { println!("hello"); } - }); + }).join(); } fn main() {} diff --git a/src/test/run-pass/issue-20676.rs b/src/test/run-pass/issue-20676.rs index df4c392385..a301622741 100644 --- a/src/test/run-pass/issue-20676.rs +++ b/src/test/run-pass/issue-20676.rs @@ -12,7 +12,6 @@ // UFCS-style calls to a method in `Trait` where `Self` was bound to a // trait object of type `Trait`. See also `ufcs-trait-object.rs`. -// pretty-expanded FIXME #23616 use std::fmt; diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs index d7a656be7a..c384757c5e 100644 --- a/src/test/run-pass/issue-21058.rs +++ b/src/test/run-pass/issue-21058.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/issue-21245.rs b/src/test/run-pass/issue-21245.rs index 75d064a00f..e3340d9767 100644 --- a/src/test/run-pass/issue-21245.rs +++ b/src/test/run-pass/issue-21245.rs @@ -20,19 +20,19 @@ use std::ptr; trait IntoIterator { type Iter: Iterator; - fn into_iter(self) -> Self::Iter; + fn into_iter2(self) -> Self::Iter; } impl IntoIterator for I where I: Iterator { type Iter = I; - fn into_iter(self) -> I { + fn into_iter2(self) -> I { self } } fn desugared_for_loop_bad(v: Vec) { - match IntoIterator::into_iter(v.iter()) { + match IntoIterator::into_iter2(v.iter()) { mut iter => { loop { match ::std::iter::Iterator::next(&mut iter) { diff --git a/src/test/run-pass/issue-21291.rs b/src/test/run-pass/issue-21291.rs new file mode 100644 index 0000000000..ec095d4895 --- /dev/null +++ b/src/test/run-pass/issue-21291.rs @@ -0,0 +1,17 @@ +// 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. + +// Regression test for unwrapping the result of `join`, issue #21291 + +use std::thread; + +fn main() { + thread::spawn(|| {}).join().unwrap() +} diff --git a/src/test/run-pass/issue-21306.rs b/src/test/run-pass/issue-21306.rs index cabda0b500..bc2c7f0937 100644 --- a/src/test/run-pass/issue-21306.rs +++ b/src/test/run-pass/issue-21306.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Arc; diff --git a/src/test/run-pass/issue-21361.rs b/src/test/run-pass/issue-21361.rs index ef86634125..b89e07ef31 100644 --- a/src/test/run-pass/issue-21361.rs +++ b/src/test/run-pass/issue-21361.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let v = vec![1, 2, 3]; diff --git a/src/test/run-pass/issue-21384.rs b/src/test/run-pass/issue-21384.rs index 41a9ca840b..e10fcd30b9 100644 --- a/src/test/run-pass/issue-21384.rs +++ b/src/test/run-pass/issue-21384.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use ::std::ops::RangeFull; diff --git a/src/test/run-pass/issue-21400.rs b/src/test/run-pass/issue-21400.rs new file mode 100644 index 0000000000..cd55b9fbaa --- /dev/null +++ b/src/test/run-pass/issue-21400.rs @@ -0,0 +1,66 @@ +// 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. + +// Regression test for #21400 which itself was extracted from +// stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580 + +fn main() { + let mut t = Test; + assert_eq!(t.method1("one"), Ok(1)); + assert_eq!(t.method2("two"), Ok(2)); + assert_eq!(t.test(), Ok(2)); +} + +struct Test; + +impl Test { + fn method1(&mut self, _arg: &str) -> Result { + Ok(1) + } + + fn method2(self: &mut Test, _arg: &str) -> Result { + Ok(2) + } + + fn test(self: &mut Test) -> Result { + let s = format!("abcde"); + // (Originally, this invocation of method2 was saying that `s` + // does not live long enough.) + let data = match self.method2(&*s) { + Ok(r) => r, + Err(e) => return Err(e) + }; + Ok(data) + } +} + +// Below is a closer match for the original test that was failing to compile + +pub struct GitConnect; + +impl GitConnect { + fn command(self: &mut GitConnect, _s: &str) -> Result>, &str> { + unimplemented!() + } + + pub fn git_upload_pack(self: &mut GitConnect) -> Result { + let c = format!("git-upload-pack"); + + let mut out = String::new(); + let data = try!(self.command(&c)); + + for line in data.iter() { + out.push_str(&format!("{:?}", line)); + } + + Ok(out) + } +} + diff --git a/src/test/run-pass/issue-21486.rs b/src/test/run-pass/issue-21486.rs new file mode 100644 index 0000000000..7f8bd7a95f --- /dev/null +++ b/src/test/run-pass/issue-21486.rs @@ -0,0 +1,86 @@ +// 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. + +// Issue #21486: Make sure that all structures are dropped, even when +// created via FRU and control-flow breaks in the middle of +// construction. + + +use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; + +#[derive(Debug)] +struct Noisy(u8); +impl Drop for Noisy { + fn drop(&mut self) { + // println!("splat #{}", self.0); + event(self.0); + } +} + +#[allow(dead_code)] +#[derive(Debug)] +struct Foo { n0: Noisy, n1: Noisy } +impl Foo { + fn vals(&self) -> (u8, u8) { (self.n0.0, self.n1.0) } +} + +fn leak_1_ret() -> Foo { + let _old_foo = Foo { n0: Noisy(1), n1: Noisy(2) }; + Foo { n0: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, + .._old_foo + }; +} + +fn leak_2_ret() -> Foo { + let _old_foo = Foo { n0: Noisy(1), n1: Noisy(2) }; + Foo { n1: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, + .._old_foo + }; +} + +// In this case, the control flow break happens *before* we construct +// `Foo(Noisy(1),Noisy(2))`, so there should be no record of it in the +// event log. +fn leak_3_ret() -> Foo { + let _old_foo = || Foo { n0: Noisy(1), n1: Noisy(2) }; + Foo { n1: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, + .._old_foo() + }; +} + +pub fn main() { + reset_log(); + assert_eq!(leak_1_ret().vals(), (3,4)); + assert_eq!(0x01_02_03_04, event_log()); + + reset_log(); + assert_eq!(leak_2_ret().vals(), (3,4)); + assert_eq!(0x01_02_03_04, event_log()); + + reset_log(); + assert_eq!(leak_3_ret().vals(), (3,4)); + assert_eq!(0x03_04, event_log()); +} + +static LOG: AtomicUsize = ATOMIC_USIZE_INIT; + +fn reset_log() { + LOG.store(0, Ordering::SeqCst); +} + +fn event_log() -> usize { + LOG.load(Ordering::SeqCst) +} + +fn event(tag: u8) { + let old_log = LOG.load(Ordering::SeqCst); + let new_log = (old_log << 8) + tag as usize; + LOG.store(new_log, Ordering::SeqCst); +} diff --git a/src/test/run-pass/issue-21634.rs b/src/test/run-pass/issue-21634.rs index fe540e1aab..2a146ae8fc 100644 --- a/src/test/run-pass/issue-21634.rs +++ b/src/test/run-pass/issue-21634.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { if let Ok(x) = "3.1415".parse::() { diff --git a/src/test/run-pass/issue-21655.rs b/src/test/run-pass/issue-21655.rs index cb87770c56..bf01873bea 100644 --- a/src/test/run-pass/issue-21655.rs +++ b/src/test/run-pass/issue-21655.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test(it: &mut Iterator) { for x in it { diff --git a/src/test/run-pass/issue-21721.rs b/src/test/run-pass/issue-21721.rs index c34ab1b0ea..d1fc61ff6a 100644 --- a/src/test/run-pass/issue-21721.rs +++ b/src/test/run-pass/issue-21721.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { static NONE: Option<((), &'static u8)> = None; diff --git a/src/test/run-pass/issue-22036.rs b/src/test/run-pass/issue-22036.rs index e02ce5441a..43fb286f0e 100644 --- a/src/test/run-pass/issue-22036.rs +++ b/src/test/run-pass/issue-22036.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait DigitCollection: Sized { type Iter: Iterator; diff --git a/src/test/run-pass/issue-2214.rs b/src/test/run-pass/issue-2214.rs index 38895e1414..775cfb0ee4 100644 --- a/src/test/run-pass/issue-2214.rs +++ b/src/test/run-pass/issue-2214.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/issue-22356.rs b/src/test/run-pass/issue-22356.rs index a54490386d..51a871d59b 100644 --- a/src/test/run-pass/issue-22356.rs +++ b/src/test/run-pass/issue-22356.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -use std::marker::{PhantomData, PhantomFn}; +use std::marker::PhantomData; pub struct Handle(T, I); @@ -34,7 +34,7 @@ impl BufferHandle { pub type RawBufferHandle = Handle<::Buffer, String>; -pub trait Device: PhantomFn { +pub trait Device { type Buffer; } diff --git a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs index 8a0f04a2cf..af99b11c25 100644 --- a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs +++ b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs @@ -11,7 +11,6 @@ // Regression test for Issue #22536: If a type implements Copy, then // moving it must not zero the original memory. -// pretty-expanded FIXME #23616 trait Resources { type Buffer: Copy; diff --git a/src/test/run-pass/issue-22546.rs b/src/test/run-pass/issue-22546.rs new file mode 100644 index 0000000000..b3cb8a7821 --- /dev/null +++ b/src/test/run-pass/issue-22546.rs @@ -0,0 +1,54 @@ +// 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. + +// Parsing patterns with paths with type parameters (issue #22544) + +use std::default::Default; + +#[derive(Default)] +pub struct Foo(T, T); + +impl Foo { + fn foo(&self) { + match *self { + Foo::(ref x, ref y) => println!("Goodbye, World! {} {}", x, y) + } + } +} + +trait Tr { + type U; +} + +impl Tr for Foo { + type U = T; +} + +struct Wrapper { + value: T +} + +fn main() { + let Foo::(a, b) = Default::default(); + + let f = Foo(2,3); + f.foo(); + + let w = Wrapper { value: Foo(10u8, 11u8) }; + match w { + Wrapper::> { value: Foo(10, 11) } => {}, + ::Wrapper::< as Tr>::U> { value: Foo::(11, 16) } => { panic!() }, + _ => { panic!() } + } + + if let None:: = Some(8) { + panic!(); + } +} diff --git a/src/test/run-pass/issue-2311-2.rs b/src/test/run-pass/issue-2311-2.rs index c76bbaf968..a47c151255 100644 --- a/src/test/run-pass/issue-2311-2.rs +++ b/src/test/run-pass/issue-2311-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait clam { fn get(self) -> A; diff --git a/src/test/run-pass/issue-2312.rs b/src/test/run-pass/issue-2312.rs index fa056191e6..6f479c6211 100644 --- a/src/test/run-pass/issue-2312.rs +++ b/src/test/run-pass/issue-2312.rs @@ -10,7 +10,6 @@ // Testing that the B's are resolved -// pretty-expanded FIXME #23616 trait clam { fn get(self) -> A; } diff --git a/src/test/run-pass/issue-23338-ensure-param-drop-order.rs b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs new file mode 100644 index 0000000000..0815ff084f --- /dev/null +++ b/src/test/run-pass/issue-23338-ensure-param-drop-order.rs @@ -0,0 +1,171 @@ +// 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. + +// ignore-pretty : (#23623) problems when ending with // comments + +// This test is ensuring that parameters are indeed dropped after +// temporaries in a fn body. + +use std::cell::RefCell; + +use self::d::D; + +pub fn main() { + let log = RefCell::new(vec![]); + d::println(&format!("created empty log")); + test(&log); + + assert_eq!(&log.borrow()[..], + [ + // created empty log + // +-- Make D(da_0, 0) + // | +-- Make D(de_1, 1) + // | | calling foo + // | | entered foo + // | | +-- Make D(de_2, 2) + // | | | +-- Make D(da_1, 3) + // | | | | +-- Make D(de_3, 4) + // | | | | | +-- Make D(de_4, 5) + 3, // | | | +-- Drop D(da_1, 3) + // | | | | | + 4, // | | | +-- Drop D(de_3, 4) + // | | | | + // | | | | eval tail of foo + // | | | +-- Make D(de_5, 6) + // | | | | +-- Make D(de_6, 7) + 6, // | | | +-- Drop D(de_5, 6) + // | | | | | + 5, // | | | | +-- Drop D(de_4, 5) + // | | | | + 2, // | | +-- Drop D(de_2, 2) + // | | | + 1, // | +-- Drop D(de_1, 1) + // | | + 0, // +-- Drop D(da_0, 0) + // | + // | result D(de_6, 7) + 7 // +-- Drop D(de_6, 7) + + ]); +} + +fn test<'a>(log: d::Log<'a>) { + let da = D::new("da", 0, log); + let de = D::new("de", 1, log); + d::println(&format!("calling foo")); + let result = foo(da, de); + d::println(&format!("result {}", result)); +} + +fn foo<'a>(da0: D<'a>, de1: D<'a>) -> D<'a> { + d::println(&format!("entered foo")); + let de2 = de1.incr(); // creates D(de_2, 2) + let de4 = { + let _da1 = da0.incr(); // creates D(da_1, 3) + de2.incr().incr() // creates D(de_3, 4) and D(de_4, 5) + }; + d::println(&format!("eval tail of foo")); + de4.incr().incr() // creates D(de_5, 6) and D(de_6, 7) +} + +// This module provides simultaneous printouts of the dynamic extents +// of all of the D values, in addition to logging the order that each +// is dropped. + +const PREF_INDENT: u32 = 16; + +pub mod d { + #![allow(unused_parens)] + use std::fmt; + use std::mem; + use std::cell::RefCell; + + static mut counter: u32 = 0; + static mut trails: u64 = 0; + + pub type Log<'a> = &'a RefCell>; + + pub fn current_width() -> u32 { + unsafe { max_width() - trails.leading_zeros() } + } + + pub fn max_width() -> u32 { + unsafe { + (mem::size_of_val(&trails)*8) as u32 + } + } + + pub fn indent_println(my_trails: u32, s: &str) { + let mut indent: String = String::new(); + for i in 0..my_trails { + unsafe { + if trails & (1 << i) != 0 { + indent = indent + "| "; + } else { + indent = indent + " "; + } + } + } + println!("{}{}", indent, s); + } + + pub fn println(s: &str) { + indent_println(super::PREF_INDENT, s); + } + + fn first_avail() -> u32 { + unsafe { + for i in 0..64 { + if trails & (1 << i) == 0 { + return i; + } + } + } + panic!("exhausted trails"); + } + + pub struct D<'a> { + name: &'static str, i: u32, uid: u32, trail: u32, log: Log<'a> + } + + impl<'a> fmt::Display for D<'a> { + fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { + write!(w, "D({}_{}, {})", self.name, self.i, self.uid) + } + } + + impl<'a> D<'a> { + pub fn new(name: &'static str, i: u32, log: Log<'a>) -> D<'a> { + unsafe { + let trail = first_avail(); + let ctr = counter; + counter += 1; + trails |= (1 << trail); + let ret = D { + name: name, i: i, log: log, uid: ctr, trail: trail + }; + indent_println(trail, &format!("+-- Make {}", ret)); + ret + } + } + pub fn incr(&self) -> D<'a> { + D::new(self.name, self.i + 1, self.log) + } + } + + impl<'a> Drop for D<'a> { + fn drop(&mut self) { + unsafe { trails &= !(1 << self.trail); }; + self.log.borrow_mut().push(self.uid); + indent_println(self.trail, &format!("+-- Drop {}", self)); + indent_println(::PREF_INDENT, ""); + } + } +} diff --git a/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs b/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs new file mode 100644 index 0000000000..cb9e852e52 --- /dev/null +++ b/src/test/run-pass/issue-23338-params-outlive-temps-of-body.rs @@ -0,0 +1,39 @@ +// 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. + +// This is largely checking that we now accept code where temp values +// are borrowing from the input parameters (the `foo` case below). +// +// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs +// +// (The `foo2` case is just for parity with the above test, which +// shows what happens when you move the `y`-binding to the inside of +// the inner block.) + +use std::cell::RefCell; + +fn foo(x: RefCell) -> String { + x.borrow().clone() +} + +fn foo2(x: RefCell) -> String { + let y = x; + let ret = { + y.borrow().clone() + }; + ret +} + +pub fn main() { + let r = RefCell::new(format!("data")); + assert_eq!(foo(r), "data"); + let r = RefCell::new(format!("data")); + assert_eq!(foo2(r), "data"); +} diff --git a/src/test/run-pass/issue-24161.rs b/src/test/run-pass/issue-24161.rs new file mode 100644 index 0000000000..2445ef17ec --- /dev/null +++ b/src/test/run-pass/issue-24161.rs @@ -0,0 +1,19 @@ +// 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. + +#[derive(Copy,Clone)] +struct Functions { + a: fn(u32) -> u32, + b: extern "C" fn(u32) -> u32, + c: unsafe fn(u32) -> u32, + d: unsafe extern "C" fn(u32) -> u32 +} + +pub fn main() {} diff --git a/src/test/run-pass/issue-2428.rs b/src/test/run-pass/issue-2428.rs index 402eb0349a..a07050d458 100644 --- a/src/test/run-pass/issue-2428.rs +++ b/src/test/run-pass/issue-2428.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _foo = 100; diff --git a/src/test/run-pass/issue-24434.rs b/src/test/run-pass/issue-24434.rs new file mode 100644 index 0000000000..2b0d09d746 --- /dev/null +++ b/src/test/run-pass/issue-24434.rs @@ -0,0 +1,16 @@ +// 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. + +// compile-flags:--cfg set1 + +#![cfg_attr(set1, feature(custom_attribute))] + +#![foobar] +fn main() {} diff --git a/src/test/run-pass/issue-2611-3.rs b/src/test/run-pass/issue-2611-3.rs index 8cf80333e9..242528dcb1 100644 --- a/src/test/run-pass/issue-2611-3.rs +++ b/src/test/run-pass/issue-2611-3.rs @@ -11,7 +11,6 @@ // Tests that impls are allowed to have looser, more permissive bounds // than the traits require. -// pretty-expanded FIXME #23616 trait A { fn b(&self, x: C) -> C; diff --git a/src/test/run-pass/issue-2735-2.rs b/src/test/run-pass/issue-2735-2.rs index 1506b2d6bf..36d7f4583b 100644 --- a/src/test/run-pass/issue-2735-2.rs +++ b/src/test/run-pass/issue-2735-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-2735-3.rs b/src/test/run-pass/issue-2735-3.rs index 2282334d66..f438519b72 100644 --- a/src/test/run-pass/issue-2735-3.rs +++ b/src/test/run-pass/issue-2735-3.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-2748-b.rs b/src/test/run-pass/issue-2748-b.rs index 8f30d262f4..f1cbf11a34 100644 --- a/src/test/run-pass/issue-2748-b.rs +++ b/src/test/run-pass/issue-2748-b.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn thing<'r>(x: &'r [isize]) -> &'r [isize] { x } diff --git a/src/test/run-pass/issue-2895.rs b/src/test/run-pass/issue-2895.rs index 3f4c630cc2..93d9300edf 100644 --- a/src/test/run-pass/issue-2895.rs +++ b/src/test/run-pass/issue-2895.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index b05baa24b7..2c45d664d8 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -11,10 +11,8 @@ // Map representation -#![feature(old_io)] - -use std::old_io; use std::fmt; +use std::io::prelude::*; use square::{bot, wall, rock, lambda, closed_lift, open_lift, earth, empty}; enum square { @@ -60,9 +58,9 @@ fn square_from_char(c: char) -> square { } } -fn read_board_grid(mut input: rdr) +fn read_board_grid(mut input: rdr) -> Vec> { - let mut input: &mut old_io::Reader = &mut input; + let mut input: &mut Read = &mut input; let mut grid = Vec::new(); let mut line = [0; 10]; input.read(&mut line); diff --git a/src/test/run-pass/issue-2936.rs b/src/test/run-pass/issue-2936.rs index 5c63230f5d..c277073a79 100644 --- a/src/test/run-pass/issue-2936.rs +++ b/src/test/run-pass/issue-2936.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait bar { fn get_bar(&self) -> T; diff --git a/src/test/run-pass/issue-3091.rs b/src/test/run-pass/issue-3091.rs index 8e59e46fc3..c67399a89e 100644 --- a/src/test/run-pass/issue-3091.rs +++ b/src/test/run-pass/issue-3091.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 1; diff --git a/src/test/run-pass/issue-3290.rs b/src/test/run-pass/issue-3290.rs index 3fa5b72c34..b09820146f 100644 --- a/src/test/run-pass/issue-3290.rs +++ b/src/test/run-pass/issue-3290.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/issue-333.rs b/src/test/run-pass/issue-333.rs index b611f11a0a..592ff0b02a 100644 --- a/src/test/run-pass/issue-333.rs +++ b/src/test/run-pass/issue-333.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn quux(x: T) -> T { let f = id::; return f(x); } diff --git a/src/test/run-pass/issue-3424.rs b/src/test/run-pass/issue-3424.rs index 29d963bb70..74e58f31e2 100644 --- a/src/test/run-pass/issue-3424.rs +++ b/src/test/run-pass/issue-3424.rs @@ -10,24 +10,17 @@ // rustc --test ignores2.rs && ./ignores2 -#![allow(unknown_features)] -#![feature(unboxed_closures, old_path, std_misc)] +pub struct Path; -use std::old_path::Path; -use std::old_path; -use std::result; -use std::thunk::Thunk; - -type rsrc_loader = Box (result::Result) + 'static>; +type rsrc_loader = Box Result>; fn tester() { - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - let mut loader: rsrc_loader = Box::new(move|_path| { - result::Result::Ok("more blah".to_string()) + let mut loader: rsrc_loader = Box::new(move |_path| { + Ok("more blah".to_string()) }); - let path = old_path::Path::new("blah"); + let path = Path; assert!(loader(&path).is_ok()); } diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 2bd270f9b0..0efa85e232 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -44,5 +44,5 @@ pub fn main() "foo".to_string(), "foo".to_string(), "foo".to_string(), "foo".to_string()); let v = format!("{:?}", u); // this is the line that causes the seg fault - assert!(v.len() > 0); + assert!(!v.is_empty()); } diff --git a/src/test/run-pass/issue-3574.rs b/src/test/run-pass/issue-3574.rs index 9a521ba376..9aac52fa2f 100644 --- a/src/test/run-pass/issue-3574.rs +++ b/src/test/run-pass/issue-3574.rs @@ -10,7 +10,6 @@ // rustc --test match_borrowed_str.rs.rs && ./match_borrowed_str.rs -// pretty-expanded FIXME #23616 fn compare(x: &str, y: &str) -> bool { match x { diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index 2167a3df97..61de3c6385 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -23,7 +23,7 @@ enum Msg } fn foo(name: String, samples_chan: Sender) { - let _t = thread::scoped(move|| { + thread::spawn(move|| { let mut samples_chan = samples_chan; // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. @@ -34,7 +34,7 @@ fn foo(name: String, samples_chan: Sender) { }); samples_chan.send(Msg::GetSamples(name.clone(), callback)); - }); + }).join(); } pub fn main() {} diff --git a/src/test/run-pass/issue-3895.rs b/src/test/run-pass/issue-3895.rs index ca6d9faf88..ffe14dab30 100644 --- a/src/test/run-pass/issue-3895.rs +++ b/src/test/run-pass/issue-3895.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { enum State { BadChar, BadSyntax } diff --git a/src/test/run-pass/issue-3935.rs b/src/test/run-pass/issue-3935.rs index 1e200e0162..45ff20fc0a 100644 --- a/src/test/run-pass/issue-3935.rs +++ b/src/test/run-pass/issue-3935.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(PartialEq)] struct Bike { diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index 61708acf7f..6ba566012c 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Add; diff --git a/src/test/run-pass/issue-3979-xcrate.rs b/src/test/run-pass/issue-3979-xcrate.rs index 0784877849..acacc48856 100644 --- a/src/test/run-pass/issue-3979-xcrate.rs +++ b/src/test/run-pass/issue-3979-xcrate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:issue_3979_traits.rs -// pretty-expanded FIXME #23616 extern crate issue_3979_traits; use issue_3979_traits::{Positioned, Movable}; diff --git a/src/test/run-pass/issue-3979.rs b/src/test/run-pass/issue-3979.rs index 341866e498..184682255d 100644 --- a/src/test/run-pass/issue-3979.rs +++ b/src/test/run-pass/issue-3979.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Positioned { fn SetX(&mut self, isize); diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index 122de97c99..bc3fa162e0 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/issue-4107.rs b/src/test/run-pass/issue-4107.rs index 18025c315c..fa5ed26847 100644 --- a/src/test/run-pass/issue-4107.rs +++ b/src/test/run-pass/issue-4107.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _id: &Mat2 = &Matrix::identity(1.0); diff --git a/src/test/run-pass/issue-4446.rs b/src/test/run-pass/issue-4446.rs index 9f8d93461a..9292a9c608 100644 --- a/src/test/run-pass/issue-4446.rs +++ b/src/test/run-pass/issue-4446.rs @@ -8,11 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io)] - -use std::old_io::println; use std::sync::mpsc::channel; use std::thread; @@ -22,6 +17,6 @@ pub fn main() { tx.send("hello, world").unwrap(); thread::spawn(move|| { - println(rx.recv().unwrap()); + println!("{}", rx.recv().unwrap()); }).join().ok().unwrap(); } diff --git a/src/test/run-pass/issue-4448.rs b/src/test/run-pass/issue-4448.rs index d5d3122f68..eb411ff441 100644 --- a/src/test/run-pass/issue-4448.rs +++ b/src/test/run-pass/issue-4448.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; use std::thread; diff --git a/src/test/run-pass/issue-4734.rs b/src/test/run-pass/issue-4734.rs index 82925852a6..88a3b24d14 100644 --- a/src/test/run-pass/issue-4734.rs +++ b/src/test/run-pass/issue-4734.rs @@ -11,7 +11,6 @@ // Ensures that destructors are run for expressions of the form "e;" where // `e` is a type which requires a destructor. -// pretty-expanded FIXME #23616 #![allow(path_statement)] diff --git a/src/test/run-pass/issue-5239-2.rs b/src/test/run-pass/issue-5239-2.rs index d8491070bd..5e58d76d5e 100644 --- a/src/test/run-pass/issue-5239-2.rs +++ b/src/test/run-pass/issue-5239-2.rs @@ -10,7 +10,6 @@ // Regression test for issue #5239 -// pretty-expanded FIXME #23616 pub fn main() { let _f = |ref x: isize| { *x }; diff --git a/src/test/run-pass/issue-5521.rs b/src/test/run-pass/issue-5521.rs index 4ad729f1bc..136f7aa956 100644 --- a/src/test/run-pass/issue-5521.rs +++ b/src/test/run-pass/issue-5521.rs @@ -11,7 +11,6 @@ // aux-build:issue-5521.rs -// pretty-expanded FIXME #23616 extern crate issue_5521 as foo; diff --git a/src/test/run-pass/issue-5530.rs b/src/test/run-pass/issue-5530.rs index 50b9ca6e79..bd7d7af71d 100644 --- a/src/test/run-pass/issue-5530.rs +++ b/src/test/run-pass/issue-5530.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Enum { Foo { foo: usize }, diff --git a/src/test/run-pass/issue-5917.rs b/src/test/run-pass/issue-5917.rs index 7f741182f4..112ad0185d 100644 --- a/src/test/run-pass/issue-5917.rs +++ b/src/test/run-pass/issue-5917.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct T (&'static [isize]); static t : T = T (&[5, 4, 3]); diff --git a/src/test/run-pass/issue-5988.rs b/src/test/run-pass/issue-5988.rs index 8ec88d5572..2cf0089c6b 100644 --- a/src/test/run-pass/issue-5988.rs +++ b/src/test/run-pass/issue-5988.rs @@ -10,9 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(old_io)] - -use std::old_io; trait B { fn f(&self); } @@ -23,7 +20,7 @@ trait T : B { struct A; impl B for U { - fn f(&self) { old_io::println("Hey, I'm a T!"); } + fn f(&self) { } } impl T for A { diff --git a/src/test/run-pass/issue-5997.rs b/src/test/run-pass/issue-5997.rs index 48923bc82b..0c41acf04a 100644 --- a/src/test/run-pass/issue-5997.rs +++ b/src/test/run-pass/issue-5997.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> bool { enum E { V(T) } diff --git a/src/test/run-pass/issue-6128.rs b/src/test/run-pass/issue-6128.rs index baf829bc26..5fb24fe3ef 100644 --- a/src/test/run-pass/issue-6128.rs +++ b/src/test/run-pass/issue-6128.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, collections)] diff --git a/src/test/run-pass/issue-6130.rs b/src/test/run-pass/issue-6130.rs index 6f15833916..f124b851f0 100644 --- a/src/test/run-pass/issue-6130.rs +++ b/src/test/run-pass/issue-6130.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![deny(type_limits)] diff --git a/src/test/run-pass/issue-6153.rs b/src/test/run-pass/issue-6153.rs index c280ea31eb..16e7060f4b 100644 --- a/src/test/run-pass/issue-6153.rs +++ b/src/test/run-pass/issue-6153.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn swap(f: F) -> Vec where F: FnOnce(Vec) -> Vec { let x = vec!(1, 2, 3); diff --git a/src/test/run-pass/issue-6334.rs b/src/test/run-pass/issue-6334.rs index 2f2dca8fe2..fca1c296dd 100644 --- a/src/test/run-pass/issue-6334.rs +++ b/src/test/run-pass/issue-6334.rs @@ -11,7 +11,6 @@ // Tests that everything still compiles and runs fine even when // we reorder the bounds. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> usize; diff --git a/src/test/run-pass/issue-6449.rs b/src/test/run-pass/issue-6449.rs index 3b33a0ac86..09a4e28840 100644 --- a/src/test/run-pass/issue-6449.rs +++ b/src/test/run-pass/issue-6449.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar(isize), diff --git a/src/test/run-pass/issue-6892.rs b/src/test/run-pass/issue-6892.rs index 4469dcc0ce..75420ad6ff 100644 --- a/src/test/run-pass/issue-6892.rs +++ b/src/test/run-pass/issue-6892.rs @@ -11,7 +11,6 @@ // Ensures that destructors are run for expressions of the form "let _ = e;" // where `e` is a type which requires a destructor. -// pretty-expanded FIXME #23616 struct Foo; struct Bar { x: isize } diff --git a/src/test/run-pass/issue-7575.rs b/src/test/run-pass/issue-7575.rs index 727ed91ead..508ebf3f69 100644 --- a/src/test/run-pass/issue-7575.rs +++ b/src/test/run-pass/issue-7575.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn new() -> bool { false } diff --git a/src/test/run-pass/issue-7663.rs b/src/test/run-pass/issue-7663.rs index 007127aeae..7aac8d4456 100644 --- a/src/test/run-pass/issue-7663.rs +++ b/src/test/run-pass/issue-7663.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unused_imports, dead_code)] diff --git a/src/test/run-pass/issue-7784.rs b/src/test/run-pass/issue-7784.rs index e2016feeb0..224fe627e3 100644 --- a/src/test/run-pass/issue-7784.rs +++ b/src/test/run-pass/issue-7784.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/issue-8351-1.rs b/src/test/run-pass/issue-8351-1.rs index a11e14fb33..ed78b37604 100644 --- a/src/test/run-pass/issue-8351-1.rs +++ b/src/test/run-pass/issue-8351-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f: isize}, diff --git a/src/test/run-pass/issue-8351-2.rs b/src/test/run-pass/issue-8351-2.rs index 7cf221926a..1ed93915b8 100644 --- a/src/test/run-pass/issue-8351-2.rs +++ b/src/test/run-pass/issue-8351-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f: isize, b: bool}, diff --git a/src/test/run-pass/issue-8391.rs b/src/test/run-pass/issue-8391.rs index bd2e2871bd..b832c41044 100644 --- a/src/test/run-pass/issue-8391.rs +++ b/src/test/run-pass/issue-8391.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let x = match Some(1) { diff --git a/src/test/run-pass/issue-8398.rs b/src/test/run-pass/issue-8398.rs index 8eb10a199e..5c2c03f985 100644 --- a/src/test/run-pass/issue-8398.rs +++ b/src/test/run-pass/issue-8398.rs @@ -10,11 +10,11 @@ // pretty-expanded FIXME #23616 -#![feature(old_io, io)] - -use std::old_io; +pub trait Writer { + fn write(&mut self, b: &[u8]) -> Result<(), ()>; +} -fn foo(a: &mut old_io::Writer) { +fn foo(a: &mut Writer) { a.write(&[]).unwrap(); } diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs index 7d8c4ab210..4ebc43163e 100644 --- a/src/test/run-pass/issue-8460.rs +++ b/src/test/run-pass/issue-8460.rs @@ -8,36 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +#![feature(zero_one)] -#![feature(core)] - -use std::num::Int; +use std::num::Zero; use std::thread; -// Avoid using constants, which would trigger compile-time errors. -fn min_val() -> T { Int::min_value() } -fn zero() -> T { Int::zero() } - fn main() { - assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() / -1; }).join().is_err()); - assert!(thread::spawn(move|| { 1isize / zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i8 / zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i16 / zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i32 / zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i64 / zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); - assert!(thread::spawn(move|| { min_val::() % -1; }).join().is_err()); - assert!(thread::spawn(move|| { 1isize % zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i8 % zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i16 % zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i32 % zero::(); }).join().is_err()); - assert!(thread::spawn(move|| { 1i64 % zero::(); }).join().is_err()); + assert!(thread::spawn(move|| { isize::min_value() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { i8::min_value() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { i16::min_value() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { i32::min_value() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { i64::min_value() / -1; }).join().is_err()); + assert!(thread::spawn(move|| { 1isize / isize::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i8 / i8::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i16 / i16::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i32 / i32::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i64 / i64::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { isize::min_value() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { i8::min_value() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { i16::min_value() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { i32::min_value() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { i64::min_value() % -1; }).join().is_err()); + assert!(thread::spawn(move|| { 1isize % isize::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i8 % i8::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i16 % i16::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i32 % i32::zero(); }).join().is_err()); + assert!(thread::spawn(move|| { 1i64 % i64::zero(); }).join().is_err()); } diff --git a/src/test/run-pass/issue-8498.rs b/src/test/run-pass/issue-8498.rs index 825729b1e2..fae3352f9c 100644 --- a/src/test/run-pass/issue-8498.rs +++ b/src/test/run-pass/issue-8498.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { match &[(Box::new(5),Box::new(7))] { diff --git a/src/test/run-pass/issue-8709.rs b/src/test/run-pass/issue-8709.rs index 6467262929..44759cef28 100644 --- a/src/test/run-pass/issue-8709.rs +++ b/src/test/run-pass/issue-8709.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! sty { ($t:ty) => (stringify!($t)) diff --git a/src/test/run-pass/issue-8860.rs b/src/test/run-pass/issue-8860.rs index 8024eaeda8..ff562aac16 100644 --- a/src/test/run-pass/issue-8860.rs +++ b/src/test/run-pass/issue-8860.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static mut DROP: isize = 0; static mut DROP_S: isize = 0; diff --git a/src/test/run-pass/issue-8898.rs b/src/test/run-pass/issue-8898.rs index a4cad1b263..065cef2c60 100644 --- a/src/test/run-pass/issue-8898.rs +++ b/src/test/run-pass/issue-8898.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn assert_repr_eq(obj : T, expected : String) { assert_eq!(expected, format!("{:?}", obj)); diff --git a/src/test/run-pass/issue-9188.rs b/src/test/run-pass/issue-9188.rs index 0bd8a8e0d9..e2272837ef 100644 --- a/src/test/run-pass/issue-9188.rs +++ b/src/test/run-pass/issue-9188.rs @@ -10,7 +10,6 @@ // aux-build:issue_9188.rs -// pretty-expanded FIXME #23616 extern crate issue_9188; diff --git a/src/test/run-pass/issue-9259.rs b/src/test/run-pass/issue-9259.rs index 209c6b1396..996548de81 100644 --- a/src/test/run-pass/issue-9259.rs +++ b/src/test/run-pass/issue-9259.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A<'a> { a: &'a [String], diff --git a/src/test/run-pass/issue-9394-inherited-trait-calls.rs b/src/test/run-pass/issue-9394-inherited-trait-calls.rs index 148d0760e5..7d2c435b38 100644 --- a/src/test/run-pass/issue-9394-inherited-trait-calls.rs +++ b/src/test/run-pass/issue-9394-inherited-trait-calls.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Base: Base2 + Base3{ fn foo(&self) -> String; diff --git a/src/test/run-pass/issue-9396.rs b/src/test/run-pass/issue-9396.rs index bfaf060e43..ed67630bca 100644 --- a/src/test/run-pass/issue-9396.rs +++ b/src/test/run-pass/issue-9396.rs @@ -8,20 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![feature(old_io, std_misc)] - use std::sync::mpsc::{TryRecvError, channel}; -use std::old_io::timer::Timer; use std::thread; -use std::time::Duration; pub fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move||{ - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(10)); + let t = thread::spawn(move||{ + thread::sleep_ms(10); tx.send(()).unwrap(); }); loop { @@ -31,4 +24,5 @@ pub fn main() { Err(TryRecvError::Disconnected) => unreachable!() } } + t.join(); } diff --git a/src/test/run-pass/issue-979.rs b/src/test/run-pass/issue-979.rs index 3283dc44f3..979abcef7b 100644 --- a/src/test/run-pass/issue-979.rs +++ b/src/test/run-pass/issue-979.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/issue-9918.rs b/src/test/run-pass/issue-9918.rs index e81a07fa68..a766e6b707 100644 --- a/src/test/run-pass/issue-9918.rs +++ b/src/test/run-pass/issue-9918.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!((0 + 0u8) as char, '\0'); diff --git a/src/test/run-pass/issue24353.rs b/src/test/run-pass/issue24353.rs new file mode 100644 index 0000000000..7a41a01392 --- /dev/null +++ b/src/test/run-pass/issue24353.rs @@ -0,0 +1,16 @@ +// 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. + +fn main() { + return (); + + let x = (); + x +} diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index c2ed68fc5d..f1ac96ab63 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -12,7 +12,6 @@ // for completeness since .rs files linked from .rc files support this // notation to specify their module's attributes -// pretty-expanded FIXME #23616 #![feature(custom_attribute, libc)] #![allow(unused_attribute)] diff --git a/src/test/run-pass/iter-cloned-type-inference.rs b/src/test/run-pass/iter-cloned-type-inference.rs index 12f6a7caf6..59f7569d8c 100644 --- a/src/test/run-pass/iter-cloned-type-inference.rs +++ b/src/test/run-pass/iter-cloned-type-inference.rs @@ -11,14 +11,11 @@ // Test to see that the element type of .cloned() can be inferred // properly. Previously this would fail to deduce the type of `sum`. -// pretty-expanded FIXME #23616 #![feature(core)] -use std::iter::AdditiveIterator; - fn square_sum(v: &[i64]) -> i64 { - let sum = v.iter().cloned().sum(); + let sum: i64 = v.iter().cloned().sum(); sum * sum } diff --git a/src/test/run-pass/ivec-tag.rs b/src/test/run-pass/ivec-tag.rs index 8ae084dce8..3f0daf2610 100644 --- a/src/test/run-pass/ivec-tag.rs +++ b/src/test/run-pass/ivec-tag.rs @@ -23,9 +23,10 @@ fn producer(tx: &Sender>) { pub fn main() { let (tx, rx) = channel::>(); - let _prod = thread::scoped(move|| { + let prod = thread::spawn(move|| { producer(&tx) }); let _data: Vec = rx.recv().unwrap(); + prod.join(); } diff --git a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs index 11b1d70137..a81c0846a2 100644 --- a/src/test/run-pass/kindck-implicit-close-over-mut-var.rs +++ b/src/test/run-pass/kindck-implicit-close-over-mut-var.rs @@ -18,12 +18,13 @@ fn foo() { // Here, i is *copied* into the proc (heap closure). // Requires allocation. The proc's copy is not mutable. let mut i = 0; - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { user(i); println!("spawned {}", i) }); i += 1; - println!("original {}", i) + println!("original {}", i); + t.join(); } fn bar() { @@ -31,10 +32,11 @@ fn bar() { // mutable outside of the proc. let mut i = 0; while i < 10 { - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { user(i); }); i += 1; + t.join(); } } @@ -42,12 +44,13 @@ fn car() { // Here, i must be shadowed in the proc to be mutable. let mut i = 0; while i < 10 { - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { let mut i = i; i += 1; user(i); }); i += 1; + t.join(); } } diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs index 84156385ef..9df72f4760 100644 --- a/src/test/run-pass/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/last-use-in-block.rs b/src/test/run-pass/last-use-in-block.rs index 28fe3bf0bd..a2b01f29ae 100644 --- a/src/test/run-pass/last-use-in-block.rs +++ b/src/test/run-pass/last-use-in-block.rs @@ -10,7 +10,6 @@ // Issue #1818 -// pretty-expanded FIXME #23616 fn lp(s: String, mut f: F) -> T where F: FnMut(String) -> T { while false { diff --git a/src/test/run-pass/last-use-in-cap-clause.rs b/src/test/run-pass/last-use-in-cap-clause.rs index f9c8fe0f2d..f196899f69 100644 --- a/src/test/run-pass/last-use-in-cap-clause.rs +++ b/src/test/run-pass/last-use-in-cap-clause.rs @@ -10,7 +10,6 @@ // Make sure #1399 stays fixed -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/let-destruct-ref.rs b/src/test/run-pass/let-destruct-ref.rs index 0b38d16941..c9504f87c4 100644 --- a/src/test/run-pass/let-destruct-ref.rs +++ b/src/test/run-pass/let-destruct-ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 3_usize; diff --git a/src/test/run-pass/let-var-hygiene.rs b/src/test/run-pass/let-var-hygiene.rs index c1e80aaf2d..d9087f58be 100644 --- a/src/test/run-pass/let-var-hygiene.rs +++ b/src/test/run-pass/let-var-hygiene.rs @@ -9,7 +9,6 @@ // except according to those terms. // shouldn't affect evaluation of $ex: -// pretty-expanded FIXME #23616 macro_rules! bad_macro { ($ex:expr) => ({let _x = 9; $ex}) diff --git a/src/test/run-pass/logging-enabled-debug.rs b/src/test/run-pass/logging-enabled-debug.rs index 59f5b0af35..3ae4884ce4 100644 --- a/src/test/run-pass/logging-enabled-debug.rs +++ b/src/test/run-pass/logging-enabled-debug.rs @@ -11,7 +11,6 @@ // compile-flags:-C debug-assertions=no // exec-env:RUST_LOG=logging-enabled-debug=debug -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/logging-enabled.rs b/src/test/run-pass/logging-enabled.rs index 294d4d1217..2975835a27 100644 --- a/src/test/run-pass/logging-enabled.rs +++ b/src/test/run-pass/logging-enabled.rs @@ -10,7 +10,6 @@ // exec-env:RUST_LOG=logging_enabled=info -// pretty-expanded FIXME #23616 #![feature(rustc_private)] diff --git a/src/test/run-pass/logging-separate-lines.rs b/src/test/run-pass/logging-separate-lines.rs index b27080b65b..29cfe91eba 100644 --- a/src/test/run-pass/logging-separate-lines.rs +++ b/src/test/run-pass/logging-separate-lines.rs @@ -17,7 +17,7 @@ #[macro_use] extern crate log; -use std::old_io::Command; +use std::process::Command; use std::env; use std::str; @@ -31,9 +31,9 @@ fn main() { let p = Command::new(&args[0]) .arg("child") - .spawn().unwrap().wait_with_output().unwrap(); + .output().unwrap(); assert!(p.status.success()); - let mut lines = str::from_utf8(&p.error).unwrap().lines(); + let mut lines = str::from_utf8(&p.stderr).unwrap().lines(); assert!(lines.next().unwrap().contains("foo")); assert!(lines.next().unwrap().contains("bar")); } diff --git a/src/test/run-pass/loop-break-cont-1.rs b/src/test/run-pass/loop-break-cont-1.rs index eaf69dbae0..5abac0e65a 100644 --- a/src/test/run-pass/loop-break-cont-1.rs +++ b/src/test/run-pass/loop-break-cont-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _i = 0_usize; diff --git a/src/test/run-pass/loop-scope.rs b/src/test/run-pass/loop-scope.rs index 70f2830555..0c1e7916cd 100644 --- a/src/test/run-pass/loop-scope.rs +++ b/src/test/run-pass/loop-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = vec!(10, 20, 30); diff --git a/src/test/run-pass/macro-block-nonterminal.rs b/src/test/run-pass/macro-block-nonterminal.rs index 496534a536..21b284f420 100644 --- a/src/test/run-pass/macro-block-nonterminal.rs +++ b/src/test/run-pass/macro-block-nonterminal.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! do_block{ ($val:block) => {$val} diff --git a/src/test/run-pass/macro-crate-def-only.rs b/src/test/run-pass/macro-crate-def-only.rs index 58b09fa492..28be058b9a 100644 --- a/src/test/run-pass/macro-crate-def-only.rs +++ b/src/test/run-pass/macro-crate-def-only.rs @@ -10,7 +10,6 @@ // aux-build:macro_crate_def_only.rs -// pretty-expanded FIXME #23616 #[macro_use] #[no_link] extern crate macro_crate_def_only; diff --git a/src/test/run-pass/macro-crate-use.rs b/src/test/run-pass/macro-crate-use.rs index 557f982713..c7255f67fa 100644 --- a/src/test/run-pass/macro-crate-use.rs +++ b/src/test/run-pass/macro-crate-use.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn increment(x: usize) -> usize { x + 1 diff --git a/src/test/run-pass/macro-deep_expansion.rs b/src/test/run-pass/macro-deep_expansion.rs index fd21ed0150..3e8548ff49 100644 --- a/src/test/run-pass/macro-deep_expansion.rs +++ b/src/test/run-pass/macro-deep_expansion.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! foo2 { () => { diff --git a/src/test/run-pass/macro-interpolation.rs b/src/test/run-pass/macro-interpolation.rs index e6b5d50b36..6dcd1538eb 100644 --- a/src/test/run-pass/macro-interpolation.rs +++ b/src/test/run-pass/macro-interpolation.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! overly_complicated { ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) => diff --git a/src/test/run-pass/macro-method-issue-4621.rs b/src/test/run-pass/macro-method-issue-4621.rs index cb15404597..64648cae5e 100644 --- a/src/test/run-pass/macro-method-issue-4621.rs +++ b/src/test/run-pass/macro-method-issue-4621.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A; diff --git a/src/test/run-pass/macro-nested_stmt_macros.rs b/src/test/run-pass/macro-nested_stmt_macros.rs new file mode 100644 index 0000000000..5997a4f18e --- /dev/null +++ b/src/test/run-pass/macro-nested_stmt_macros.rs @@ -0,0 +1,32 @@ +// 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. + +macro_rules! foo { + () => { + struct Bar; + struct Baz; + } +} + +macro_rules! grault { + () => { + foo!(); + struct Xyzzy; + } +} + +fn static_assert_exists() { } + +fn main() { + grault!(); + static_assert_exists::(); + static_assert_exists::(); + static_assert_exists::(); +} diff --git a/src/test/run-pass/macro-of-higher-order.rs b/src/test/run-pass/macro-of-higher-order.rs index ebd58f7722..52e19b37d7 100644 --- a/src/test/run-pass/macro-of-higher-order.rs +++ b/src/test/run-pass/macro-of-higher-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! higher_order { (subst $lhs:tt => $rhs:tt) => ({ diff --git a/src/test/run-pass/macro-pat.rs b/src/test/run-pass/macro-pat.rs index 659113d4e0..48e521de57 100644 --- a/src/test/run-pass/macro-pat.rs +++ b/src/test/run-pass/macro-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 macro_rules! mypat { () => ( diff --git a/src/test/run-pass/macro-path.rs b/src/test/run-pass/macro-path.rs index 2e88062297..7aecc1dc20 100644 --- a/src/test/run-pass/macro-path.rs +++ b/src/test/run-pass/macro-path.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod m { pub type t = isize; diff --git a/src/test/run-pass/macro-stmt_macro_in_expr_macro.rs b/src/test/run-pass/macro-stmt_macro_in_expr_macro.rs new file mode 100644 index 0000000000..c5badd78a6 --- /dev/null +++ b/src/test/run-pass/macro-stmt_macro_in_expr_macro.rs @@ -0,0 +1,29 @@ +// 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. + +macro_rules! foo { + () => { + struct Bar; + struct Baz; + } +} + +macro_rules! grault { + () => {{ + foo!(); + struct Xyzzy; + 0 + }} +} + +fn main() { + let x = grault!(); + assert_eq!(x, 0); +} diff --git a/src/test/run-pass/macro-with-attrs1.rs b/src/test/run-pass/macro-with-attrs1.rs index 0938c16c30..99bf71b1f0 100644 --- a/src/test/run-pass/macro-with-attrs1.rs +++ b/src/test/run-pass/macro-with-attrs1.rs @@ -10,7 +10,6 @@ // compile-flags: --cfg foo -// pretty-expanded FIXME #23616 #[cfg(foo)] macro_rules! foo { () => (1) } diff --git a/src/test/run-pass/macro-with-attrs2.rs b/src/test/run-pass/macro-with-attrs2.rs index cf48c325f1..062c8d55d5 100644 --- a/src/test/run-pass/macro-with-attrs2.rs +++ b/src/test/run-pass/macro-with-attrs2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[cfg(foo)] macro_rules! foo { () => (1) } diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index 1b4dfb869d..43ff69fe75 100644 --- a/src/test/run-pass/match-arm-statics.rs +++ b/src/test/run-pass/match-arm-statics.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct NewBool(bool); diff --git a/src/test/run-pass/match-borrowed_str.rs b/src/test/run-pass/match-borrowed_str.rs index 574c4b9f00..b027e62494 100644 --- a/src/test/run-pass/match-borrowed_str.rs +++ b/src/test/run-pass/match-borrowed_str.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unnecessary_allocation)] diff --git a/src/test/run-pass/match-bot-2.rs b/src/test/run-pass/match-bot-2.rs index 4fa951b347..88c514a724 100644 --- a/src/test/run-pass/match-bot-2.rs +++ b/src/test/run-pass/match-bot-2.rs @@ -9,7 +9,6 @@ // except according to those terms. // n.b. This was only ever failing with optimization disabled. -// pretty-expanded FIXME #23616 fn a() -> isize { match return 1 { 2 => 3, _ => panic!() } } pub fn main() { a(); } diff --git a/src/test/run-pass/match-enum-struct-0.rs b/src/test/run-pass/match-enum-struct-0.rs index 06d19cec18..1754dc0c96 100644 --- a/src/test/run-pass/match-enum-struct-0.rs +++ b/src/test/run-pass/match-enum-struct-0.rs @@ -10,7 +10,6 @@ // regression test for issue #5625 -// pretty-expanded FIXME #23616 enum E { Foo{f : isize}, diff --git a/src/test/run-pass/match-enum-struct-1.rs b/src/test/run-pass/match-enum-struct-1.rs index e4766f32a5..ebf2db3670 100644 --- a/src/test/run-pass/match-enum-struct-1.rs +++ b/src/test/run-pass/match-enum-struct-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum E { Foo{f : isize}, diff --git a/src/test/run-pass/match-implicit-copy-unique.rs b/src/test/run-pass/match-implicit-copy-unique.rs index d481c02eb4..d75bdaf4da 100644 --- a/src/test/run-pass/match-implicit-copy-unique.rs +++ b/src/test/run-pass/match-implicit-copy-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/match-in-macro.rs b/src/test/run-pass/match-in-macro.rs index 27bbbc936a..e096c97e16 100644 --- a/src/test/run-pass/match-in-macro.rs +++ b/src/test/run-pass/match-in-macro.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { B { b1: isize, bb1: isize}, diff --git a/src/test/run-pass/match-pattern-bindings.rs b/src/test/run-pass/match-pattern-bindings.rs index d230f18f2b..9f687ab99e 100644 --- a/src/test/run-pass/match-pattern-bindings.rs +++ b/src/test/run-pass/match-pattern-bindings.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let value = Some(1); diff --git a/src/test/run-pass/match-pipe-binding.rs b/src/test/run-pass/match-pipe-binding.rs index 70d3639a78..bda90d3aae 100644 --- a/src/test/run-pass/match-pipe-binding.rs +++ b/src/test/run-pass/match-pipe-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test1() { // from issue 6338 diff --git a/src/test/run-pass/match-ref-binding-in-guard-3256.rs b/src/test/run-pass/match-ref-binding-in-guard-3256.rs index 1e2ebf42a9..dc3c759078 100644 --- a/src/test/run-pass/match-ref-binding-in-guard-3256.rs +++ b/src/test/run-pass/match-ref-binding-in-guard-3256.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Mutex; diff --git a/src/test/run-pass/match-ref-binding-mut-option.rs b/src/test/run-pass/match-ref-binding-mut-option.rs index 41f00e58ff..f429e7b58e 100644 --- a/src/test/run-pass/match-ref-binding-mut-option.rs +++ b/src/test/run-pass/match-ref-binding-mut-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut v = Some(22); diff --git a/src/test/run-pass/match-ref-binding-mut.rs b/src/test/run-pass/match-ref-binding-mut.rs index 26c91e1703..abc418ddd5 100644 --- a/src/test/run-pass/match-ref-binding-mut.rs +++ b/src/test/run-pass/match-ref-binding-mut.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Rec { f: isize diff --git a/src/test/run-pass/match-ref-binding.rs b/src/test/run-pass/match-ref-binding.rs index 826edb30b3..eab7ed529b 100644 --- a/src/test/run-pass/match-ref-binding.rs +++ b/src/test/run-pass/match-ref-binding.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn destructure(x: Option) -> isize { match x { diff --git a/src/test/run-pass/match-static-const-rename.rs b/src/test/run-pass/match-static-const-rename.rs index 21b806f80d..08f3182900 100644 --- a/src/test/run-pass/match-static-const-rename.rs +++ b/src/test/run-pass/match-static-const-rename.rs @@ -16,7 +16,6 @@ // around this problem locally by renaming the constant in the `use` // form to an uppercase identifier that placates the lint. -// pretty-expanded FIXME #23616 #![deny(non_upper_case_globals)] diff --git a/src/test/run-pass/match-str.rs b/src/test/run-pass/match-str.rs index 5d8958c6b9..e6def65e53 100644 --- a/src/test/run-pass/match-str.rs +++ b/src/test/run-pass/match-str.rs @@ -10,7 +10,6 @@ // Issue #53 -// pretty-expanded FIXME #23616 pub fn main() { match "test" { "not-test" => panic!(), "test" => (), _ => panic!() } diff --git a/src/test/run-pass/match-struct-0.rs b/src/test/run-pass/match-struct-0.rs index 450b310b8f..e9e45df460 100644 --- a/src/test/run-pass/match-struct-0.rs +++ b/src/test/run-pass/match-struct-0.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo{ f : isize, diff --git a/src/test/run-pass/match-tag.rs b/src/test/run-pass/match-tag.rs index 82d29f9050..e4a0d4e95f 100644 --- a/src/test/run-pass/match-tag.rs +++ b/src/test/run-pass/match-tag.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 enum color { rgb(isize, isize, isize), diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index f9b49281ba..43e0b44225 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/match-vec-rvalue.rs b/src/test/run-pass/match-vec-rvalue.rs index e368aeb976..a10f9b1d7d 100644 --- a/src/test/run-pass/match-vec-rvalue.rs +++ b/src/test/run-pass/match-vec-rvalue.rs @@ -11,7 +11,6 @@ // Tests that matching rvalues with drops does not crash. -// pretty-expanded FIXME #23616 pub fn main() { match vec!(1, 2, 3) { diff --git a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs index 7cc762c934..1611a2c072 100644 --- a/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs +++ b/src/test/run-pass/method-mut-self-modifies-mut-slice-lvalue.rs @@ -12,13 +12,13 @@ // type is `&mut [u8]`, passes in a pointer to the lvalue and not a // temporary. Issue #19147. -// pretty-expanded FIXME #23616 #![feature(core, old_io)] use std::mem; use std::slice; -use std::old_io::IoResult; + +pub type IoResult = Result; trait MyWriter { fn my_write(&mut self, buf: &[u8]) -> IoResult<()>; diff --git a/src/test/run-pass/method-projection.rs b/src/test/run-pass/method-projection.rs index 3db7268207..41d92cc759 100644 --- a/src/test/run-pass/method-projection.rs +++ b/src/test/run-pass/method-projection.rs @@ -13,7 +13,6 @@ /////////////////////////////////////////////////////////////////////////// -// pretty-expanded FIXME #23616 trait MakeString { fn make_string(&self) -> String; diff --git a/src/test/run-pass/method-self-arg-aux1.rs b/src/test/run-pass/method-self-arg-aux1.rs index 768e7f9486..acda78af5c 100644 --- a/src/test/run-pass/method-self-arg-aux1.rs +++ b/src/test/run-pass/method-self-arg-aux1.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument (cross-crate) -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg-aux2.rs b/src/test/run-pass/method-self-arg-aux2.rs index b40333c67c..0aea4139b0 100644 --- a/src/test/run-pass/method-self-arg-aux2.rs +++ b/src/test/run-pass/method-self-arg-aux2.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument (cross-crate) -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg-trait.rs b/src/test/run-pass/method-self-arg-trait.rs index f0ca0a70ac..2ba3e78ef1 100644 --- a/src/test/run-pass/method-self-arg-trait.rs +++ b/src/test/run-pass/method-self-arg-trait.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-self-arg.rs b/src/test/run-pass/method-self-arg.rs index dfc1211922..543133a326 100644 --- a/src/test/run-pass/method-self-arg.rs +++ b/src/test/run-pass/method-self-arg.rs @@ -10,7 +10,6 @@ // Test method calls with self as an argument -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-two-trait-defer-resolution-1.rs b/src/test/run-pass/method-two-trait-defer-resolution-1.rs index d0e0427f37..ff80ee1986 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-1.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-1.rs @@ -11,7 +11,6 @@ // Test that we pick which version of `foo` to run based on the // type that is (ultimately) inferred for `x`. -// pretty-expanded FIXME #23616 trait foo { fn foo(&self) -> i32; diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index 2ceff22adb..cf9bc9bb56 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that when we write `x.foo()`, we do nothave to know the +// Test that when we write `x.foo()`, we do not have to know the // complete type of `x` in order to type-check the method call. In // this case, we know that `x: Vec<_1>`, but we don't know what type // `_1` is (because the call to `push` comes later). To pick between @@ -19,7 +19,6 @@ // translate the call as `Foo::foo(&x)` and let the specific impl get // chosen later. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/method-where-clause.rs b/src/test/run-pass/method-where-clause.rs index f2ff0abfad..078dbe0e79 100644 --- a/src/test/run-pass/method-where-clause.rs +++ b/src/test/run-pass/method-where-clause.rs @@ -11,7 +11,6 @@ // Test that we can use method notation to call methods based on a // where clause type, and not only type parameters. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> i32; diff --git a/src/test/run-pass/mod-inside-fn.rs b/src/test/run-pass/mod-inside-fn.rs index 836f2960d7..6b922634aa 100644 --- a/src/test/run-pass/mod-inside-fn.rs +++ b/src/test/run-pass/mod-inside-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f() -> isize { mod m { diff --git a/src/test/run-pass/monad.rs b/src/test/run-pass/monad.rs index 9ccb8f2e6f..e309fa1430 100644 --- a/src/test/run-pass/monad.rs +++ b/src/test/run-pass/monad.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 trait vec_monad { fn bind(&self, f: F ) -> Vec where F: FnMut(&A) -> Vec ; diff --git a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs index 12162ba902..b7de1b5f4c 100644 --- a/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs +++ b/src/test/run-pass/monomorphized-callees-with-ty-params-3314.rs @@ -10,11 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::marker::MarkerTrait; - -trait Serializer : MarkerTrait { +trait Serializer { } trait Serializable { diff --git a/src/test/run-pass/move-1-unique.rs b/src/test/run-pass/move-1-unique.rs index ab9770b13d..34a3bdf876 100644 --- a/src/test/run-pass/move-1-unique.rs +++ b/src/test/run-pass/move-1-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-2-unique.rs b/src/test/run-pass/move-2-unique.rs index c65e58a7b6..e4dc82f980 100644 --- a/src/test/run-pass/move-2-unique.rs +++ b/src/test/run-pass/move-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-2.rs b/src/test/run-pass/move-2.rs index 054b57b2f4..0c89c89eb8 100644 --- a/src/test/run-pass/move-2.rs +++ b/src/test/run-pass/move-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-3-unique.rs b/src/test/run-pass/move-3-unique.rs index 6036fa26cc..360593ffe4 100644 --- a/src/test/run-pass/move-3-unique.rs +++ b/src/test/run-pass/move-3-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-4-unique.rs b/src/test/run-pass/move-4-unique.rs index 79a1b294da..9f80ecf297 100644 --- a/src/test/run-pass/move-4-unique.rs +++ b/src/test/run-pass/move-4-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-4.rs b/src/test/run-pass/move-4.rs index 16ef950235..1346860d51 100644 --- a/src/test/run-pass/move-4.rs +++ b/src/test/run-pass/move-4.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg-2-unique.rs b/src/test/run-pass/move-arg-2-unique.rs index 7aec948c8d..fa69731963 100644 --- a/src/test/run-pass/move-arg-2-unique.rs +++ b/src/test/run-pass/move-arg-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg-2.rs b/src/test/run-pass/move-arg-2.rs index 69b66d81e4..6e22deed26 100644 --- a/src/test/run-pass/move-arg-2.rs +++ b/src/test/run-pass/move-arg-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/move-arg.rs b/src/test/run-pass/move-arg.rs index 3d9eba8c09..0ff9a35874 100644 --- a/src/test/run-pass/move-arg.rs +++ b/src/test/run-pass/move-arg.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test(foo: isize) { assert!((foo == 10)); } diff --git a/src/test/run-pass/move-out-of-field.rs b/src/test/run-pass/move-out-of-field.rs index a0eba4685b..262add090b 100644 --- a/src/test/run-pass/move-out-of-field.rs +++ b/src/test/run-pass/move-out-of-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::string::String; diff --git a/src/test/run-pass/move-scalar.rs b/src/test/run-pass/move-scalar.rs index a5b0a8b9bf..798424d107 100644 --- a/src/test/run-pass/move-scalar.rs +++ b/src/test/run-pass/move-scalar.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { diff --git a/src/test/run-pass/moves-based-on-type-capture-clause.rs b/src/test/run-pass/moves-based-on-type-capture-clause.rs index b6509d2803..c7ef977636 100644 --- a/src/test/run-pass/moves-based-on-type-capture-clause.rs +++ b/src/test/run-pass/moves-based-on-type-capture-clause.rs @@ -14,7 +14,7 @@ use std::thread; pub fn main() { let x = "Hello world!".to_string(); - let _t = thread::scoped(move|| { + thread::spawn(move|| { println!("{}", x); - }); + }).join(); } diff --git a/src/test/run-pass/multi-let.rs b/src/test/run-pass/multi-let.rs index 658b34e13f..1079857c1b 100644 --- a/src/test/run-pass/multi-let.rs +++ b/src/test/run-pass/multi-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let x = 10; diff --git a/src/test/run-pass/multidispatch1.rs b/src/test/run-pass/multidispatch1.rs index fdf9f95b27..7137a4109b 100644 --- a/src/test/run-pass/multidispatch1.rs +++ b/src/test/run-pass/multidispatch1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::fmt::Debug; diff --git a/src/test/run-pass/multidispatch2.rs b/src/test/run-pass/multidispatch2.rs index 75c6c5ac7d..1573c0234a 100644 --- a/src/test/run-pass/multidispatch2.rs +++ b/src/test/run-pass/multidispatch2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::fmt::Debug; use std::default::Default; diff --git a/src/test/run-pass/mut-function-arguments.rs b/src/test/run-pass/mut-function-arguments.rs index 644e455755..f415a7f2d6 100644 --- a/src/test/run-pass/mut-function-arguments.rs +++ b/src/test/run-pass/mut-function-arguments.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/mut-in-ident-patterns.rs b/src/test/run-pass/mut-in-ident-patterns.rs index 2a8f6f1fc3..32ff7efffa 100644 --- a/src/test/run-pass/mut-in-ident-patterns.rs +++ b/src/test/run-pass/mut-in-ident-patterns.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self, mut x: isize) -> isize { diff --git a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs index bed3b87def..1766e65b9c 100644 --- a/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs +++ b/src/test/run-pass/mutability-inherits-through-fixed-length-vec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn test1() { let mut ints = [0; 32]; diff --git a/src/test/run-pass/negative.rs b/src/test/run-pass/negative.rs index c5b6a6a035..df074ddc06 100644 --- a/src/test/run-pass/negative.rs +++ b/src/test/run-pass/negative.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { match -5 { diff --git a/src/test/run-pass/nested-class.rs b/src/test/run-pass/nested-class.rs index 86197d44a6..1ad68cb9de 100644 --- a/src/test/run-pass/nested-class.rs +++ b/src/test/run-pass/nested-class.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { struct b { diff --git a/src/test/run-pass/nested-function-names-issue-8587.rs b/src/test/run-pass/nested-function-names-issue-8587.rs index 28f3438f98..24b1f5ac75 100644 --- a/src/test/run-pass/nested-function-names-issue-8587.rs +++ b/src/test/run-pass/nested-function-names-issue-8587.rs @@ -13,7 +13,6 @@ // // Issue #8587 -// pretty-expanded FIXME #23616 pub struct X; diff --git a/src/test/run-pass/nested_item_main.rs b/src/test/run-pass/nested_item_main.rs index f7adfe3669..b24d517f73 100644 --- a/src/test/run-pass/nested_item_main.rs +++ b/src/test/run-pass/nested_item_main.rs @@ -10,7 +10,6 @@ // aux-build:nested_item.rs -// pretty-expanded FIXME #23616 extern crate nested_item; diff --git a/src/test/run-pass/new-unicode-escapes.rs b/src/test/run-pass/new-unicode-escapes.rs index 8c2d5e09ad..bfad79e92d 100644 --- a/src/test/run-pass/new-unicode-escapes.rs +++ b/src/test/run-pass/new-unicode-escapes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/newlambdas.rs b/src/test/run-pass/newlambdas.rs index c6fa7cc35f..a6f3995863 100644 --- a/src/test/run-pass/newlambdas.rs +++ b/src/test/run-pass/newlambdas.rs @@ -10,7 +10,6 @@ // Tests for the new |args| expr lambda syntax -// pretty-expanded FIXME #23616 fn f(i: isize, f: F) -> isize where F: FnOnce(isize) -> isize { f(i) } diff --git a/src/test/run-pass/newtype-polymorphic.rs b/src/test/run-pass/newtype-polymorphic.rs index 424d518895..91599608ce 100644 --- a/src/test/run-pass/newtype-polymorphic.rs +++ b/src/test/run-pass/newtype-polymorphic.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Clone)] struct myvec(Vec ); diff --git a/src/test/run-pass/newtype-struct-drop-run.rs b/src/test/run-pass/newtype-struct-drop-run.rs index 2d162ba7e3..4407002aca 100644 --- a/src/test/run-pass/newtype-struct-drop-run.rs +++ b/src/test/run-pass/newtype-struct-drop-run.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/no-landing-pads.rs b/src/test/run-pass/no-landing-pads.rs index da57c81a66..d90e7ef5e4 100644 --- a/src/test/run-pass/no-landing-pads.rs +++ b/src/test/run-pass/no-landing-pads.rs @@ -10,7 +10,6 @@ // compile-flags: -Z no-landing-pads -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/non-legacy-modes.rs b/src/test/run-pass/non-legacy-modes.rs index 5f1c69bb4b..58534ed96d 100644 --- a/src/test/run-pass/non-legacy-modes.rs +++ b/src/test/run-pass/non-legacy-modes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct X { repr: isize diff --git a/src/test/run-pass/nul-characters.rs b/src/test/run-pass/nul-characters.rs index 25c111daad..cbea5e71f2 100644 --- a/src/test/run-pass/nul-characters.rs +++ b/src/test/run-pass/nul-characters.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index 22aa09c718..224111900d 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -20,7 +20,6 @@ // then we simply express the enum as just a pointer and not wrap it // in a struct. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index ad2716e00d..ced2b24f36 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/nullable-pointer-size.rs b/src/test/run-pass/nullable-pointer-size.rs index 6e3f438575..b097d350c8 100644 --- a/src/test/run-pass/nullable-pointer-size.rs +++ b/src/test/run-pass/nullable-pointer-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/nullary-or-pattern.rs b/src/test/run-pass/nullary-or-pattern.rs index f4cfc80827..feb8726c0e 100644 --- a/src/test/run-pass/nullary-or-pattern.rs +++ b/src/test/run-pass/nullary-or-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum blah { a, b, } diff --git a/src/test/run-pass/numeric-method-autoexport.rs b/src/test/run-pass/numeric-method-autoexport.rs index cb41949a72..b1d71abc78 100644 --- a/src/test/run-pass/numeric-method-autoexport.rs +++ b/src/test/run-pass/numeric-method-autoexport.rs @@ -15,12 +15,7 @@ // necessary. Testing the methods of the impls is done within the source // file for each numeric type. -// pretty-expanded FIXME #23616 - -#![feature(core)] - use std::ops::Add; -use std::num::ToPrimitive; pub fn main() { // ints @@ -38,9 +33,4 @@ pub fn main() { assert_eq!(15_u16.add(6u16), 21_u16); assert_eq!(15_u32.add(6u32), 21_u32); assert_eq!(15_u64.add(6u64), 21_u64); - -// floats - // num - assert_eq!(10_f32.to_i32().unwrap(), 10); - assert_eq!(10_f64.to_i32().unwrap(), 10); } diff --git a/src/test/run-pass/object-method-numbering.rs b/src/test/run-pass/object-method-numbering.rs index 8b8c56aee8..82d34fa9ae 100644 --- a/src/test/run-pass/object-method-numbering.rs +++ b/src/test/run-pass/object-method-numbering.rs @@ -11,7 +11,6 @@ // Test for using an object with an associated type binding as the // instantiation for a generic type with a bound. -// pretty-expanded FIXME #23616 trait SomeTrait { type SomeType; diff --git a/src/test/run-pass/object-safety-sized-self-by-value-self.rs b/src/test/run-pass/object-safety-sized-self-by-value-self.rs index b735743927..81acd94ebe 100644 --- a/src/test/run-pass/object-safety-sized-self-by-value-self.rs +++ b/src/test/run-pass/object-safety-sized-self-by-value-self.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // methods with by-value self so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn tick(&mut self) -> u32; diff --git a/src/test/run-pass/object-safety-sized-self-generic-method.rs b/src/test/run-pass/object-safety-sized-self-generic-method.rs index 696c5a0970..2e84117566 100644 --- a/src/test/run-pass/object-safety-sized-self-generic-method.rs +++ b/src/test/run-pass/object-safety-sized-self-generic-method.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // generic methods so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn tick(&mut self) -> u32; diff --git a/src/test/run-pass/object-safety-sized-self-return-Self.rs b/src/test/run-pass/object-safety-sized-self-return-Self.rs index 17c41f2194..eda541262b 100644 --- a/src/test/run-pass/object-safety-sized-self-return-Self.rs +++ b/src/test/run-pass/object-safety-sized-self-return-Self.rs @@ -11,7 +11,6 @@ // Check that a trait is still object-safe (and usable) if it has // methods that return `Self` so long as they require `Self : Sized`. -// pretty-expanded FIXME #23616 trait Counter { fn new() -> Self where Self : Sized; diff --git a/src/test/run-pass/objects-coerce-freeze-borrored.rs b/src/test/run-pass/objects-coerce-freeze-borrored.rs index 686924a314..f907b5723f 100644 --- a/src/test/run-pass/objects-coerce-freeze-borrored.rs +++ b/src/test/run-pass/objects-coerce-freeze-borrored.rs @@ -10,7 +10,6 @@ // Test that we can coerce an `@Object` to an `&Object` -// pretty-expanded FIXME #23616 trait Foo { fn foo(&self) -> usize; diff --git a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs index 9a1cdd2922..176f67fd3a 100644 --- a/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs +++ b/src/test/run-pass/objects-owned-object-borrowed-method-headerless.rs @@ -12,7 +12,6 @@ // closed over do not contain managed values, and thus the boxes do // not have headers. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/objects-owned-object-owned-method.rs b/src/test/run-pass/objects-owned-object-owned-method.rs index 4357adbf65..71ed995e76 100644 --- a/src/test/run-pass/objects-owned-object-owned-method.rs +++ b/src/test/run-pass/objects-owned-object-owned-method.rs @@ -12,7 +12,6 @@ // closed over contain managed values. This implies that the boxes // will have headers that must be skipped over. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs index 7bf8b693d9..6dd4c0ddce 100644 --- a/src/test/run-pass/once-move-out-on-heap.rs +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -11,7 +11,6 @@ // Testing guarantees provided by once functions. -// pretty-expanded FIXME #23616 use std::sync::Arc; diff --git a/src/test/run-pass/one-tuple.rs b/src/test/run-pass/one-tuple.rs index 6520e42dbe..68974b47d0 100644 --- a/src/test/run-pass/one-tuple.rs +++ b/src/test/run-pass/one-tuple.rs @@ -10,7 +10,6 @@ // Why one-tuples? Because macros. -// pretty-expanded FIXME #23616 pub fn main() { match ('c',) { diff --git a/src/test/run-pass/operator-associativity.rs b/src/test/run-pass/operator-associativity.rs index ccfdb83ab8..78834ef914 100644 --- a/src/test/run-pass/operator-associativity.rs +++ b/src/test/run-pass/operator-associativity.rs @@ -12,6 +12,5 @@ // Testcase for issue #130, operator associativity. -// pretty-expanded FIXME #23616 pub fn main() { assert!((3 * 5 / 2 == 7)); } diff --git a/src/test/run-pass/option-unwrap.rs b/src/test/run-pass/option-unwrap.rs index 4902038667..44f13a3eb1 100644 --- a/src/test/run-pass/option-unwrap.rs +++ b/src/test/run-pass/option-unwrap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/or-pattern.rs b/src/test/run-pass/or-pattern.rs index 3ab78e8d05..3bb0c71c58 100644 --- a/src/test/run-pass/or-pattern.rs +++ b/src/test/run-pass/or-pattern.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum blah { a(isize, isize, usize), b(isize, isize), c, } diff --git a/src/test/run-pass/order-drop-with-match.rs b/src/test/run-pass/order-drop-with-match.rs index c8a2ba0af4..8f82e3aaba 100644 --- a/src/test/run-pass/order-drop-with-match.rs +++ b/src/test/run-pass/order-drop-with-match.rs @@ -14,7 +14,6 @@ // in ORDER matching up to when it ran. // Correct order is: matched, inner, outer -// pretty-expanded FIXME #23616 static mut ORDER: [usize; 3] = [0, 0, 0]; static mut INDEX: usize = 0; diff --git a/src/test/run-pass/out-of-stack-new-thread-no-split.rs b/src/test/run-pass/out-of-stack-new-thread-no-split.rs index f08ed6e7f9..0d0a5bee8a 100644 --- a/src/test/run-pass/out-of-stack-new-thread-no-split.rs +++ b/src/test/run-pass/out-of-stack-new-thread-no-split.rs @@ -14,9 +14,9 @@ //ignore-dragonfly //ignore-bitrig -#![feature(asm, old_io, std_misc)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; use std::thread; @@ -37,11 +37,11 @@ fn recurse() { fn main() { let args: Vec = env::args().collect(); if args.len() > 1 && args[1] == "recurse" { - let _t = thread::scoped(recurse); + thread::spawn(recurse).join(); } else { let recurse = Command::new(&args[0]).arg("recurse").output().unwrap(); assert!(!recurse.status.success()); - let error = String::from_utf8_lossy(&recurse.error); + let error = String::from_utf8_lossy(&recurse.stderr); println!("wut"); println!("`{}`", error); assert!(error.contains("has overflowed its stack")); diff --git a/src/test/run-pass/out-of-stack-no-split.rs b/src/test/run-pass/out-of-stack-no-split.rs index 8887e1937c..da7342d251 100644 --- a/src/test/run-pass/out-of-stack-no-split.rs +++ b/src/test/run-pass/out-of-stack-no-split.rs @@ -8,16 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-android -//ignore-linux -//ignore-freebsd -//ignore-ios -//ignore-dragonfly -//ignore-bitrig +// ignore-android +// ignore-linux +// ignore-freebsd +// ignore-ios +// ignore-dragonfly +// ignore-bitrig -#![feature(asm, old_io)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; // lifted from the test module @@ -41,7 +41,7 @@ fn main() { } else { let recurse = Command::new(&args[0]).arg("recurse").output().unwrap(); assert!(!recurse.status.success()); - let error = String::from_utf8_lossy(&recurse.error); + let error = String::from_utf8_lossy(&recurse.stderr); assert!(error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index 47f83eab4c..d90b88cbfd 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -10,9 +10,9 @@ // ignore-android: FIXME (#20004) -#![feature(asm, old_io)] +#![feature(asm)] -use std::old_io::process::Command; +use std::process::Command; use std::env; // lifted from the test module @@ -42,12 +42,12 @@ fn main() { } else { let silent = Command::new(&args[0]).arg("silent").output().unwrap(); assert!(!silent.status.success()); - let error = String::from_utf8_lossy(&silent.error); + let error = String::from_utf8_lossy(&silent.stderr); assert!(error.contains("has overflowed its stack")); let loud = Command::new(&args[0]).arg("loud").output().unwrap(); assert!(!loud.status.success()); - let error = String::from_utf8_lossy(&silent.error); + let error = String::from_utf8_lossy(&silent.stderr); assert!(error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/out-pointer-aliasing.rs b/src/test/run-pass/out-pointer-aliasing.rs index 0a58411041..790affd939 100644 --- a/src/test/run-pass/out-pointer-aliasing.rs +++ b/src/test/run-pass/out-pointer-aliasing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] pub struct Foo { diff --git a/src/test/run-pass/overloaded-autoderef-indexing.rs b/src/test/run-pass/overloaded-autoderef-indexing.rs index fdf42423b6..67b8bc1d15 100644 --- a/src/test/run-pass/overloaded-autoderef-indexing.rs +++ b/src/test/run-pass/overloaded-autoderef-indexing.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-order.rs b/src/test/run-pass/overloaded-autoderef-order.rs index 6880032e69..7433494dec 100644 --- a/src/test/run-pass/overloaded-autoderef-order.rs +++ b/src/test/run-pass/overloaded-autoderef-order.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::rc::Rc; use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-vtable.rs b/src/test/run-pass/overloaded-autoderef-vtable.rs index 38bf68b746..ed11c8c0ba 100644 --- a/src/test/run-pass/overloaded-autoderef-vtable.rs +++ b/src/test/run-pass/overloaded-autoderef-vtable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::ops::Deref; diff --git a/src/test/run-pass/overloaded-autoderef-xcrate.rs b/src/test/run-pass/overloaded-autoderef-xcrate.rs index b97fb49112..174e09cb14 100644 --- a/src/test/run-pass/overloaded-autoderef-xcrate.rs +++ b/src/test/run-pass/overloaded-autoderef-xcrate.rs @@ -10,7 +10,6 @@ // aux-build:overloaded_autoderef_xc.rs -// pretty-expanded FIXME #23616 extern crate overloaded_autoderef_xc; diff --git a/src/test/run-pass/overloaded-autoderef.rs b/src/test/run-pass/overloaded-autoderef.rs index ddd6ae4d0a..5e924d015b 100644 --- a/src/test/run-pass/overloaded-autoderef.rs +++ b/src/test/run-pass/overloaded-autoderef.rs @@ -13,7 +13,6 @@ use std::cell::RefCell; use std::rc::Rc; -use std::num::ToPrimitive; #[derive(PartialEq, Debug)] struct Point { @@ -23,9 +22,6 @@ struct Point { pub fn main() { let box_5: Box<_> = box 5_usize; - assert_eq!(Rc::new(5_usize).to_uint(), Some(5)); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. - assert_eq!((Box::new(&Box::new(&Rc::new(Box::new(Box::new(&box_5)))))).to_uint(), Some(5)); let point = Rc::new(Point {x: 2, y: 4}); assert_eq!(point.x, 2); assert_eq!(point.y, 4); diff --git a/src/test/run-pass/overloaded-calls-object-one-arg.rs b/src/test/run-pass/overloaded-calls-object-one-arg.rs index 291d2c6498..ec64f627c9 100644 --- a/src/test/run-pass/overloaded-calls-object-one-arg.rs +++ b/src/test/run-pass/overloaded-calls-object-one-arg.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 1 argument. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut(isize) -> isize) -> isize { f(22) diff --git a/src/test/run-pass/overloaded-calls-object-two-args.rs b/src/test/run-pass/overloaded-calls-object-two-args.rs index 42c71572a3..c38a62147a 100644 --- a/src/test/run-pass/overloaded-calls-object-two-args.rs +++ b/src/test/run-pass/overloaded-calls-object-two-args.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 2 arguments. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut(isize, isize) -> isize) -> isize { f(1, 2) diff --git a/src/test/run-pass/overloaded-calls-object-zero-args.rs b/src/test/run-pass/overloaded-calls-object-zero-args.rs index 9bc6c9f042..08ab465ebb 100644 --- a/src/test/run-pass/overloaded-calls-object-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-object-zero-args.rs @@ -11,7 +11,6 @@ // Tests calls to closure arguments where the closure takes 0 arguments. // This is a bit tricky due to rust-call ABI. -// pretty-expanded FIXME #23616 fn foo(f: &mut FnMut() -> isize) -> isize { f() diff --git a/src/test/run-pass/overloaded-calls-simple.rs b/src/test/run-pass/overloaded-calls-simple.rs index eeb705a2e3..6566f6c126 100644 --- a/src/test/run-pass/overloaded-calls-simple.rs +++ b/src/test/run-pass/overloaded-calls-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures, core)] diff --git a/src/test/run-pass/overloaded-calls-zero-args.rs b/src/test/run-pass/overloaded-calls-zero-args.rs index 8df4adf671..621b2f9420 100644 --- a/src/test/run-pass/overloaded-calls-zero-args.rs +++ b/src/test/run-pass/overloaded-calls-zero-args.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 5f6eb87ae1..a8a3b3014e 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::cell::Cell; use std::ops::{Deref, DerefMut}; diff --git a/src/test/run-pass/overloaded-index-assoc-list.rs b/src/test/run-pass/overloaded-index-assoc-list.rs index 131098d7c9..455099f1eb 100644 --- a/src/test/run-pass/overloaded-index-assoc-list.rs +++ b/src/test/run-pass/overloaded-index-assoc-list.rs @@ -11,7 +11,6 @@ // Test overloading of the `[]` operator. In particular test that it // takes its argument *by reference*. -// pretty-expanded FIXME #23616 #![feature(core)] @@ -35,7 +34,7 @@ impl AssociationList { impl<'a, K: PartialEq + std::fmt::Debug, V:Clone> Index<&'a K> for AssociationList { type Output = V; - fn index<'a>(&'a self, index: &K) -> &'a V { + fn index(&self, index: &K) -> &V { for pair in &self.pairs { if pair.key == *index { return &pair.value diff --git a/src/test/run-pass/overloaded-index-autoderef.rs b/src/test/run-pass/overloaded-index-autoderef.rs index 56d71edd56..efa0051493 100644 --- a/src/test/run-pass/overloaded-index-autoderef.rs +++ b/src/test/run-pass/overloaded-index-autoderef.rs @@ -10,7 +10,6 @@ // Test overloaded indexing combined with autoderef. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/overloaded-index-in-field.rs b/src/test/run-pass/overloaded-index-in-field.rs index bc53836aca..ff867e7681 100644 --- a/src/test/run-pass/overloaded-index-in-field.rs +++ b/src/test/run-pass/overloaded-index-in-field.rs @@ -11,7 +11,6 @@ // Test using overloaded indexing when the "map" is stored in a // field. This caused problems at some point. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/overloaded-index.rs b/src/test/run-pass/overloaded-index.rs index 4f8cf0e9e3..fa3c107697 100644 --- a/src/test/run-pass/overloaded-index.rs +++ b/src/test/run-pass/overloaded-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs index 8819b20136..4886874062 100644 --- a/src/test/run-pass/packed-struct-borrow-element.rs +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[repr(packed)] struct Foo { diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs index 5d518749d9..e03772ddf9 100644 --- a/src/test/run-pass/packed-struct-generic-layout.rs +++ b/src/test/run-pass/packed-struct-generic-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs index 6c24b71971..4e1f62b28a 100644 --- a/src/test/run-pass/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs index 5d2454be2f..2ac07a5d7e 100644 --- a/src/test/run-pass/packed-struct-layout.rs +++ b/src/test/run-pass/packed-struct-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs index 3c3d632222..3cd254014c 100644 --- a/src/test/run-pass/packed-struct-match.rs +++ b/src/test/run-pass/packed-struct-match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[repr(packed)] struct Foo { diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs index b7ea720caf..372693433d 100644 --- a/src/test/run-pass/packed-struct-size-xc.rs +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -10,7 +10,6 @@ // aux-build:packed.rs -// pretty-expanded FIXME #23616 extern crate packed; diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs index 3d748c4042..754a357333 100644 --- a/src/test/run-pass/packed-struct-size.rs +++ b/src/test/run-pass/packed-struct-size.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs index 9d96adc29d..376aadc735 100644 --- a/src/test/run-pass/packed-tuple-struct-layout.rs +++ b/src/test/run-pass/packed-tuple-struct-layout.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs index 7b7cd59298..b0c8684cfe 100644 --- a/src/test/run-pass/packed-tuple-struct-size.rs +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/panic-in-dtor-drops-fields.rs b/src/test/run-pass/panic-in-dtor-drops-fields.rs index 4226fba9d3..f84a823d3d 100644 --- a/src/test/run-pass/panic-in-dtor-drops-fields.rs +++ b/src/test/run-pass/panic-in-dtor-drops-fields.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/pat-ranges.rs b/src/test/run-pass/pat-ranges.rs new file mode 100644 index 0000000000..964989508c --- /dev/null +++ b/src/test/run-pass/pat-ranges.rs @@ -0,0 +1,23 @@ +// 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. + +// Parsing of range patterns + +const NUM1: i32 = 10; + +mod m { + pub const NUM2: i32 = 16; +} + +fn main() { + if let NUM1 ... m::NUM2 = 10 {} else { panic!() } + if let ::NUM1 ... ::m::NUM2 = 11 {} else { panic!() } + if let -13 ... -10 = 12 { panic!() } else {} +} diff --git a/src/test/run-pass/pattern-bound-var-in-for-each.rs b/src/test/run-pass/pattern-bound-var-in-for-each.rs index 1ab578b933..59ead3e3e9 100644 --- a/src/test/run-pass/pattern-bound-var-in-for-each.rs +++ b/src/test/run-pass/pattern-bound-var-in-for-each.rs @@ -12,7 +12,6 @@ // pattern-bound var is an upvar (when translating // the for-each body) -// pretty-expanded FIXME #23616 fn foo(src: usize) { diff --git a/src/test/run-pass/private-class-field.rs b/src/test/run-pass/private-class-field.rs index d32ac4b908..8c92a05ba2 100644 --- a/src/test/run-pass/private-class-field.rs +++ b/src/test/run-pass/private-class-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct cat { meows : usize, diff --git a/src/test/run-pass/process-remove-from-env.rs b/src/test/run-pass/process-remove-from-env.rs index 6429352f44..3096fe4a26 100644 --- a/src/test/run-pass/process-remove-from-env.rs +++ b/src/test/run-pass/process-remove-from-env.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 -#![feature(old_io)] - -use std::old_io::Command; +use std::process::Command; use std::env; #[cfg(all(unix, not(target_os="android")))] @@ -50,7 +47,7 @@ fn main() { let prog = cmd.spawn().unwrap(); let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output); + let output = String::from_utf8_lossy(&result.stdout); assert!(!output.contains("RUN_TEST_NEW_ENV"), "found RUN_TEST_NEW_ENV inside of:\n\n{}", output); diff --git a/src/test/run-pass/range-type-infer.rs b/src/test/run-pass/range-type-infer.rs index 2d664c00ed..b6d4d09d69 100644 --- a/src/test/run-pass/range-type-infer.rs +++ b/src/test/run-pass/range-type-infer.rs @@ -12,7 +12,6 @@ // good as the old one. Check out issue #21672, #21595 and #21649 for // more details. -// pretty-expanded FIXME #23616 fn main() { let xs = (0..8).map(|i| i == 1u64).collect::>(); diff --git a/src/test/run-pass/range.rs b/src/test/run-pass/range.rs index 4633f73b9a..03a8af319e 100644 --- a/src/test/run-pass/range.rs +++ b/src/test/run-pass/range.rs @@ -10,7 +10,6 @@ // Test range syntax. -// pretty-expanded FIXME #23616 fn foo() -> isize { 42 } diff --git a/src/test/run-pass/ranges-precedence.rs b/src/test/run-pass/ranges-precedence.rs index 870d7a0bc0..807e23c81c 100644 --- a/src/test/run-pass/ranges-precedence.rs +++ b/src/test/run-pass/ranges-precedence.rs @@ -11,7 +11,6 @@ // Test that the precedence of ranges is correct -// pretty-expanded FIXME #23616 struct Foo { foo: usize, diff --git a/src/test/run-pass/readalias.rs b/src/test/run-pass/readalias.rs index d3b9e56f7d..29e45ce8a9 100644 --- a/src/test/run-pass/readalias.rs +++ b/src/test/run-pass/readalias.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 struct Point {x: isize, y: isize, z: isize} diff --git a/src/test/run-pass/rec-extend.rs b/src/test/run-pass/rec-extend.rs index 1071df84cd..ffef77a4b8 100644 --- a/src/test/run-pass/rec-extend.rs +++ b/src/test/run-pass/rec-extend.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 struct Point {x: isize, y: isize} diff --git a/src/test/run-pass/rec-tup.rs b/src/test/run-pass/rec-tup.rs index 1644a16942..810888b0d8 100644 --- a/src/test/run-pass/rec-tup.rs +++ b/src/test/run-pass/rec-tup.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Point {x: isize, y: isize} diff --git a/src/test/run-pass/rec.rs b/src/test/run-pass/rec.rs index a422aaba84..b47bda0931 100644 --- a/src/test/run-pass/rec.rs +++ b/src/test/run-pass/rec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Rect {x: isize, y: isize, w: isize, h: isize} diff --git a/src/test/run-pass/record-pat.rs b/src/test/run-pass/record-pat.rs index 6b39cc196f..99bec7ab7d 100644 --- a/src/test/run-pass/record-pat.rs +++ b/src/test/run-pass/record-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum t1 { a(isize), b(usize), } struct T2 {x: t1, y: isize} diff --git a/src/test/run-pass/reexported-static-methods-cross-crate.rs b/src/test/run-pass/reexported-static-methods-cross-crate.rs index 3efd913cf5..4d10503838 100644 --- a/src/test/run-pass/reexported-static-methods-cross-crate.rs +++ b/src/test/run-pass/reexported-static-methods-cross-crate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:reexported_static_methods.rs -// pretty-expanded FIXME #23616 extern crate reexported_static_methods; diff --git a/src/test/run-pass/regions-borrow-evec-fixed.rs b/src/test/run-pass/regions-borrow-evec-fixed.rs index 7f3db86783..6d1f2930ab 100644 --- a/src/test/run-pass/regions-borrow-evec-fixed.rs +++ b/src/test/run-pass/regions-borrow-evec-fixed.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &[isize]) -> isize { x[0] diff --git a/src/test/run-pass/regions-borrow-evec-uniq.rs b/src/test/run-pass/regions-borrow-evec-uniq.rs index adf88037d2..ec1f4eda28 100644 --- a/src/test/run-pass/regions-borrow-evec-uniq.rs +++ b/src/test/run-pass/regions-borrow-evec-uniq.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn foo(x: &[isize]) -> isize { x[0] diff --git a/src/test/run-pass/regions-borrow-uniq.rs b/src/test/run-pass/regions-borrow-uniq.rs index 01a4e9c20c..2a08940dab 100644 --- a/src/test/run-pass/regions-borrow-uniq.rs +++ b/src/test/run-pass/regions-borrow-uniq.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-bot.rs b/src/test/run-pass/regions-bot.rs index 269e30741f..4347cbe2dc 100644 --- a/src/test/run-pass/regions-bot.rs +++ b/src/test/run-pass/regions-bot.rs @@ -10,7 +10,6 @@ // A very limited test of the "bottom" region -// pretty-expanded FIXME #23616 fn produce_static() -> &'static T { panic!(); } diff --git a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs index cc417219ee..d048633519 100644 --- a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs +++ b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs @@ -11,7 +11,6 @@ // A test where we (successfully) close over a reference into // an object. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-copy-closure.rs b/src/test/run-pass/regions-copy-closure.rs index 9e3fe79197..3c01a7f892 100644 --- a/src/test/run-pass/regions-copy-closure.rs +++ b/src/test/run-pass/regions-copy-closure.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/regions-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs index 123806a4d9..a6a179c432 100644 --- a/src/test/run-pass/regions-dependent-addr-of.rs +++ b/src/test/run-pass/regions-dependent-addr-of.rs @@ -11,7 +11,6 @@ // Test lifetimes are linked properly when we create dependent region pointers. // Issue #3148. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/regions-early-bound-lifetime-in-assoc-fn.rs b/src/test/run-pass/regions-early-bound-lifetime-in-assoc-fn.rs index 9aed915512..0ffbc432aa 100644 --- a/src/test/run-pass/regions-early-bound-lifetime-in-assoc-fn.rs +++ b/src/test/run-pass/regions-early-bound-lifetime-in-assoc-fn.rs @@ -27,9 +27,7 @@ pub trait Decoder<'v> { fn read(&mut self) -> Value<'v>; } -pub trait Decodable<'v, D: Decoder<'v>> - : marker::PhantomFn<(), &'v isize> -{ +pub trait Decodable<'v, D: Decoder<'v>> { fn decode(d: &mut D) -> Self; } diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 738f5dbb7b..33889b27a8 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -11,7 +11,6 @@ // Tests that you can use an early-bound lifetime parameter as // on of the generic parameters in a trait. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs index 6ad8995123..c7bc8dc0a5 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait GetRef<'a> { fn get(&self) -> &'a isize; diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs index 6ab95d6e49..3c8c78aa11 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait GetRef<'a, T> { fn get(&self) -> &'a T; diff --git a/src/test/run-pass/regions-early-bound-used-in-type-param.rs b/src/test/run-pass/regions-early-bound-used-in-type-param.rs index dc991e9493..8d145fad00 100644 --- a/src/test/run-pass/regions-early-bound-used-in-type-param.rs +++ b/src/test/run-pass/regions-early-bound-used-in-type-param.rs @@ -11,7 +11,6 @@ // Tests that you can use a fn lifetime parameter as part of // the value for a type parameter in a bound. -// pretty-expanded FIXME #23616 trait Get { fn get(&self) -> T; diff --git a/src/test/run-pass/regions-escape-into-other-fn.rs b/src/test/run-pass/regions-escape-into-other-fn.rs index 3e2fec717f..597333482f 100644 --- a/src/test/run-pass/regions-escape-into-other-fn.rs +++ b/src/test/run-pass/regions-escape-into-other-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs index 5d17181173..5c80863ce8 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 9c200a370a..f9ba8e82ef 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn view(x: &[T]) -> &[T] {x} diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index 59221afcef..a89f6f4a7b 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index 3289da3cfd..01f4163731 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-infer-call-2.rs b/src/test/run-pass/regions-infer-call-2.rs index 7e6767b0de..b994bc7b85 100644 --- a/src/test/run-pass/regions-infer-call-2.rs +++ b/src/test/run-pass/regions-infer-call-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } diff --git a/src/test/run-pass/regions-infer-call.rs b/src/test/run-pass/regions-infer-call.rs index bc752a1d50..76b93f2356 100644 --- a/src/test/run-pass/regions-infer-call.rs +++ b/src/test/run-pass/regions-infer-call.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn takes_two(x: &isize, y: &isize) -> isize { *x + *y } diff --git a/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs b/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs index 73cfbcddd9..3c6bc13399 100644 --- a/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs +++ b/src/test/run-pass/regions-infer-contravariance-due-to-ret.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct boxed_int<'a> { f: &'a isize, diff --git a/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs index 451c745358..d1c1ec43b4 100644 --- a/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs +++ b/src/test/run-pass/regions-lifetime-static-items-enclosing-scopes.rs @@ -11,7 +11,6 @@ // This test verifies that temporary lifetime is correctly computed // for static objects in enclosing scopes. -// pretty-expanded FIXME #23616 use std::cmp::PartialEq; diff --git a/src/test/run-pass/regions-no-variance-from-fn-generics.rs b/src/test/run-pass/regions-no-variance-from-fn-generics.rs index 89bdbfaed9..d385804da5 100644 --- a/src/test/run-pass/regions-no-variance-from-fn-generics.rs +++ b/src/test/run-pass/regions-no-variance-from-fn-generics.rs @@ -12,7 +12,6 @@ // should not upset the variance inference for actual occurrences of // that lifetime in type expressions. -// pretty-expanded FIXME #23616 pub trait HasLife<'a> { fn dummy(&'a self) { } // just to induce a variance on 'a diff --git a/src/test/run-pass/regions-params.rs b/src/test/run-pass/regions-params.rs index 5002fcce96..dbd52bd6b6 100644 --- a/src/test/run-pass/regions-params.rs +++ b/src/test/run-pass/regions-params.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn region_identity(x: &usize) -> &usize { x } diff --git a/src/test/run-pass/regions-refcell.rs b/src/test/run-pass/regions-refcell.rs index 63525b3620..ca6a62c10c 100644 --- a/src/test/run-pass/regions-refcell.rs +++ b/src/test/run-pass/regions-refcell.rs @@ -12,7 +12,6 @@ // attempting to bootstrap librustc with new destructor lifetime // semantics. -// pretty-expanded FIXME #23616 use std::collections::HashMap; use std::cell::RefCell; diff --git a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs index a36c1b30ea..465f43e36b 100644 --- a/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/run-pass/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -17,7 +17,6 @@ // changes were caught. However, those uses in the compiler could // easily get changed or refactored away in the future. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/regions-return-interior-of-option.rs b/src/test/run-pass/regions-return-interior-of-option.rs index e6ab4a8142..fe1c68ff42 100644 --- a/src/test/run-pass/regions-return-interior-of-option.rs +++ b/src/test/run-pass/regions-return-interior-of-option.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn get(opt: &Option) -> &T { match *opt { diff --git a/src/test/run-pass/regions-trait-object-1.rs b/src/test/run-pass/regions-trait-object-1.rs index d235298857..542dc76061 100644 --- a/src/test/run-pass/regions-trait-object-1.rs +++ b/src/test/run-pass/regions-trait-object-1.rs @@ -12,7 +12,6 @@ // attempting to bootstrap libsyntax; it is adapted from // `syntax::ext::tt::generic_extension`. -// pretty-expanded FIXME #23616 pub struct E<'a> { pub f: &'a u8, diff --git a/src/test/run-pass/repeat-expr-in-static.rs b/src/test/run-pass/repeat-expr-in-static.rs index 5a4475ae94..a040d680f9 100644 --- a/src/test/run-pass/repeat-expr-in-static.rs +++ b/src/test/run-pass/repeat-expr-in-static.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 static FOO: [isize; 4] = [32; 4]; static BAR: [isize; 4] = [32, 32, 32, 32]; diff --git a/src/test/run-pass/resolve-issue-2428.rs b/src/test/run-pass/resolve-issue-2428.rs index bad5b83b54..d3bdd54624 100644 --- a/src/test/run-pass/resolve-issue-2428.rs +++ b/src/test/run-pass/resolve-issue-2428.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 const foo: isize = 4 >> 1; enum bs { thing = foo } diff --git a/src/test/run-pass/resource-in-struct.rs b/src/test/run-pass/resource-in-struct.rs index a8426f90cc..c1e1ff0658 100644 --- a/src/test/run-pass/resource-in-struct.rs +++ b/src/test/run-pass/resource-in-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/return-from-closure.rs b/src/test/run-pass/return-from-closure.rs index 4395f6fcb4..76eddd0538 100644 --- a/src/test/run-pass/return-from-closure.rs +++ b/src/test/run-pass/return-from-closure.rs @@ -10,7 +10,6 @@ // just to make sure that `return` is only returning from the closure, // not the surrounding function. -// pretty-expanded FIXME #23616 static mut calls: usize = 0; diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index abad08c7ac..31d97305e0 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -11,7 +11,7 @@ #![feature(start, os, std_misc, old_io)] use std::ffi::CStr; -use std::old_io::process::{Command, ProcessOutput}; +use std::process::{Command, Output}; use std::os; use std::rt::unwind::try; use std::rt; @@ -23,12 +23,12 @@ use std::thunk::Thunk; fn start(argc: isize, argv: *const *const u8) -> isize { if argc > 1 { unsafe { - match **argv.offset(1) { - 1 => {} - 2 => println!("foo"), - 3 => assert!(try(|| {}).is_ok()), - 4 => assert!(try(|| panic!()).is_err()), - 5 => assert!(Command::new("test").spawn().is_err()), + match **argv.offset(1) as char { + '1' => {} + '2' => println!("foo"), + '3' => assert!(try(|| {}).is_ok()), + '4' => assert!(try(|| panic!()).is_err()), + '5' => assert!(Command::new("test").spawn().is_err()), _ => panic!() } } @@ -41,25 +41,20 @@ fn start(argc: isize, argv: *const *const u8) -> isize { CStr::from_ptr(ptr).to_bytes().to_vec() }).collect::>() }; - let me = &*args[0]; + let me = String::from_utf8(args[0].to_vec()).unwrap(); - let x: &[u8] = &[1]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[2]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[3]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[4]; - pass(Command::new(me).arg(x).output().unwrap()); - let x: &[u8] = &[5]; - pass(Command::new(me).arg(x).output().unwrap()); + pass(Command::new(&me).arg("1").output().unwrap()); + pass(Command::new(&me).arg("2").output().unwrap()); + pass(Command::new(&me).arg("3").output().unwrap()); + pass(Command::new(&me).arg("4").output().unwrap()); + pass(Command::new(&me).arg("5").output().unwrap()); 0 } -fn pass(output: ProcessOutput) { +fn pass(output: Output) { if !output.status.success() { - println!("{:?}", str::from_utf8(&output.output)); - println!("{:?}", str::from_utf8(&output.error)); + println!("{:?}", str::from_utf8(&output.stdout)); + println!("{:?}", str::from_utf8(&output.stderr)); } } diff --git a/src/test/run-pass/rust-log-filter.rs b/src/test/run-pass/rust-log-filter.rs index 660b1e2036..5917920610 100644 --- a/src/test/run-pass/rust-log-filter.rs +++ b/src/test/run-pass/rust-log-filter.rs @@ -10,7 +10,6 @@ // exec-env:RUST_LOG=rust_log_filter/foo -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc, rustc_private)] @@ -41,7 +40,7 @@ impl log::Logger for ChannelLogger { pub fn main() { let (logger, rx) = ChannelLogger::new(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { log::set_logger(logger); info!("foo"); @@ -54,4 +53,6 @@ pub fn main() { assert_eq!(rx.recv().unwrap(), "foo bar"); assert_eq!(rx.recv().unwrap(), "bar foo"); assert!(rx.recv().is_err()); + + t.join(); } diff --git a/src/test/run-pass/segfault-no-out-of-stack.rs b/src/test/run-pass/segfault-no-out-of-stack.rs index 6eb9600cf8..dd33c330cf 100644 --- a/src/test/run-pass/segfault-no-out-of-stack.rs +++ b/src/test/run-pass/segfault-no-out-of-stack.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 -#![feature(old_io)] - -use std::old_io::process::Command; +use std::process::Command; use std::env; fn main() { @@ -22,7 +19,7 @@ fn main() { } else { let segfault = Command::new(&args[0]).arg("segfault").output().unwrap(); assert!(!segfault.status.success()); - let error = String::from_utf8_lossy(&segfault.error); + let error = String::from_utf8_lossy(&segfault.stderr); assert!(!error.contains("has overflowed its stack")); } } diff --git a/src/test/run-pass/self-impl.rs b/src/test/run-pass/self-impl.rs index c32773aa88..688b66a0a8 100644 --- a/src/test/run-pass/self-impl.rs +++ b/src/test/run-pass/self-impl.rs @@ -22,6 +22,17 @@ impl Foo { fn foo(_x: Self, _y: &Self, _z: Box) -> Self { Foo } + + fn baz() { + // Test that Self cannot be shadowed. + type Foo = i32; + // There is no empty method on i32. + Self::empty(); + + let _: Self = Foo; + } + + fn empty() {} } // Test uses when implementing a trait and with a type parameter. @@ -29,13 +40,31 @@ pub struct Baz { pub f: X, } -trait Bar { - fn bar(x: Self, y: &Self, z: Box) -> Self; +trait SuperBar { + type SuperQux; +} + +trait Bar: SuperBar { + type Qux; + + fn bar(x: Self, y: &Self, z: Box, _: Self::SuperQux) -> Self; fn dummy(&self, x: X) { } } +impl SuperBar for Box> { + type SuperQux = bool; +} + impl Bar for Box> { - fn bar(_x: Self, _y: &Self, _z: Box) -> Self { + type Qux = i32; + + fn bar(_x: Self, _y: &Self, _z: Box, _: Self::SuperQux) -> Self { + let _: Self::Qux = 42; + let _: >::Qux = 42; + + let _: Self::SuperQux = true; + let _: ::SuperQux = true; + box Baz { f: 42 } } } @@ -43,6 +72,7 @@ impl Bar for Box> { fn main() { let _: Foo = Foo::foo(Foo, &Foo, box Foo); let _: Box> = Bar::bar(box Baz { f: 42 }, - &box Baz { f: 42 }, - box box Baz { f: 42 }); + &box Baz { f: 42 }, + box box Baz { f: 42 }, + true); } diff --git a/src/test/run-pass/self-in-mut-slot-default-method.rs b/src/test/run-pass/self-in-mut-slot-default-method.rs index f8502137be..877988e60a 100644 --- a/src/test/run-pass/self-in-mut-slot-default-method.rs +++ b/src/test/run-pass/self-in-mut-slot-default-method.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/self-in-mut-slot-immediate-value.rs b/src/test/run-pass/self-in-mut-slot-immediate-value.rs index fa9ad9f651..24014c289f 100644 --- a/src/test/run-pass/self-in-mut-slot-immediate-value.rs +++ b/src/test/run-pass/self-in-mut-slot-immediate-value.rs @@ -11,7 +11,6 @@ // Assert that `mut self` on an immediate value doesn't // allow mutating the original - issue #10615. -// pretty-expanded FIXME #23616 #[derive(Copy, Clone)] struct Value { diff --git a/src/test/run-pass/self-re-assign.rs b/src/test/run-pass/self-re-assign.rs index b3c81cab3c..7314a65b60 100644 --- a/src/test/run-pass/self-re-assign.rs +++ b/src/test/run-pass/self-re-assign.rs @@ -11,7 +11,6 @@ // Ensure assigning an owned or managed variable to itself works. In particular, // that we do not glue_drop before we glue_take (#3290). -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/self-shadowing-import.rs b/src/test/run-pass/self-shadowing-import.rs index 5de1686ef9..cd47a0e86b 100644 --- a/src/test/run-pass/self-shadowing-import.rs +++ b/src/test/run-pass/self-shadowing-import.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod a { pub mod b { diff --git a/src/test/run-pass/send-is-not-static-par-for.rs b/src/test/run-pass/send-is-not-static-par-for.rs index 99ae3b7c7d..5f0902d34d 100644 --- a/src/test/run-pass/send-is-not-static-par-for.rs +++ b/src/test/run-pass/send-is-not-static-par-for.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(core, std_misc)] +#![feature(core, std_misc, scoped)] use std::thread; use std::sync::Mutex; @@ -25,7 +25,6 @@ fn par_for(iter: I, f: F) f(elem) }) }).collect(); - } fn sum(x: &[i32]) { diff --git a/src/test/run-pass/send-resource.rs b/src/test/run-pass/send-resource.rs index 3f64b2adb6..66878d98c8 100644 --- a/src/test/run-pass/send-resource.rs +++ b/src/test/run-pass/send-resource.rs @@ -32,7 +32,7 @@ fn test(f: isize) -> test { pub fn main() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { let (tx2, rx2) = channel(); tx.send(tx2).unwrap(); @@ -40,4 +40,6 @@ pub fn main() { }); rx.recv().unwrap().send(test(42)).unwrap(); + + t.join(); } diff --git a/src/test/run-pass/send_str_hashmap.rs b/src/test/run-pass/send_str_hashmap.rs index 16a695f08f..2501ef94be 100644 --- a/src/test/run-pass/send_str_hashmap.rs +++ b/src/test/run-pass/send_str_hashmap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, into_cow)] diff --git a/src/test/run-pass/send_str_treemap.rs b/src/test/run-pass/send_str_treemap.rs index d56657ee4d..146f525350 100644 --- a/src/test/run-pass/send_str_treemap.rs +++ b/src/test/run-pass/send_str_treemap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, into_cow)] diff --git a/src/test/run-pass/sendfn-is-a-block.rs b/src/test/run-pass/sendfn-is-a-block.rs index 59b92ec6a4..162b05f0bb 100644 --- a/src/test/run-pass/sendfn-is-a-block.rs +++ b/src/test/run-pass/sendfn-is-a-block.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 fn test(f: F) -> usize where F: FnOnce(usize) -> usize { return f(22); diff --git a/src/test/run-pass/sepcomp-cci.rs b/src/test/run-pass/sepcomp-cci.rs index 6a92f32c0b..a1c5ad113c 100644 --- a/src/test/run-pass/sepcomp-cci.rs +++ b/src/test/run-pass/sepcomp-cci.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // aux-build:sepcomp_cci_lib.rs // Test accessing cross-crate inlined items from multiple compilation units. -// pretty-expanded FIXME #23616 extern crate sepcomp_cci_lib; use sepcomp_cci_lib::{cci_fn, CCI_STATIC}; diff --git a/src/test/run-pass/sepcomp-extern.rs b/src/test/run-pass/sepcomp-extern.rs index f91c3d1ff3..973c61712c 100644 --- a/src/test/run-pass/sepcomp-extern.rs +++ b/src/test/run-pass/sepcomp-extern.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // aux-build:sepcomp-extern-lib.rs // Test accessing external items from multiple compilation units. -// pretty-expanded FIXME #23616 #[link(name = "sepcomp_extern_lib")] extern { diff --git a/src/test/run-pass/sepcomp-fns-backwards.rs b/src/test/run-pass/sepcomp-fns-backwards.rs index 2e510082e2..1ab8bc7f88 100644 --- a/src/test/run-pass/sepcomp-fns-backwards.rs +++ b/src/test/run-pass/sepcomp-fns-backwards.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // Test references to items that haven't been translated yet. @@ -15,7 +16,6 @@ // Generate some code in the first compilation unit before declaring any // modules. This ensures that the first module doesn't go into the same // compilation unit as the top-level module. -// pretty-expanded FIXME #23616 fn pad() -> usize { 0 } diff --git a/src/test/run-pass/sepcomp-fns.rs b/src/test/run-pass/sepcomp-fns.rs index f4fa0ed569..a2356cf02a 100644 --- a/src/test/run-pass/sepcomp-fns.rs +++ b/src/test/run-pass/sepcomp-fns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // Test basic separate compilation functionality. The functions should be able @@ -17,7 +18,6 @@ // Generate some code in the first compilation unit before declaring any // modules. This ensures that the first module doesn't go into the same // compilation unit as the top-level module. -// pretty-expanded FIXME #23616 fn one() -> usize { 1 } diff --git a/src/test/run-pass/sepcomp-lib.rs b/src/test/run-pass/sepcomp-lib.rs index 00e83a5705..abe842a332 100644 --- a/src/test/run-pass/sepcomp-lib.rs +++ b/src/test/run-pass/sepcomp-lib.rs @@ -12,7 +12,6 @@ // Test linking against a library built with -C codegen-units > 1 -// pretty-expanded FIXME #23616 extern crate sepcomp_lib; use sepcomp_lib::a::one; diff --git a/src/test/run-pass/sepcomp-statics.rs b/src/test/run-pass/sepcomp-statics.rs index e926114e21..8cda469a88 100644 --- a/src/test/run-pass/sepcomp-statics.rs +++ b/src/test/run-pass/sepcomp-statics.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // Test references to static items across compilation units. -// pretty-expanded FIXME #23616 fn pad() -> usize { 0 } diff --git a/src/test/run-pass/sepcomp-unwind.rs b/src/test/run-pass/sepcomp-unwind.rs index 71d3d91e84..766e2b6b72 100644 --- a/src/test/run-pass/sepcomp-unwind.rs +++ b/src/test/run-pass/sepcomp-unwind.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-bitrig // compile-flags: -C codegen-units=3 // Test unwinding through multiple compilation units. @@ -19,7 +20,6 @@ // In any case, this test should let us know if enabling parallel codegen ever // breaks unwinding. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/seq-compare.rs b/src/test/run-pass/seq-compare.rs index 743f54abcf..f1a21d90ab 100644 --- a/src/test/run-pass/seq-compare.rs +++ b/src/test/run-pass/seq-compare.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert!(("hello".to_string() < "hellr".to_string())); diff --git a/src/test/run-pass/shift-various-types.rs b/src/test/run-pass/shift-various-types.rs index b0ab72c650..9238112a08 100644 --- a/src/test/run-pass/shift-various-types.rs +++ b/src/test/run-pass/shift-various-types.rs @@ -10,7 +10,6 @@ // Test that we can do shifts by any integral type. -// pretty-expanded FIXME #23616 struct Panolpy { i8: i8, diff --git a/src/test/run-pass/shift.rs b/src/test/run-pass/shift.rs index f1637fe1e0..2f417e0e2f 100644 --- a/src/test/run-pass/shift.rs +++ b/src/test/run-pass/shift.rs @@ -11,7 +11,6 @@ // Testing shifts for various combinations of integers // Issue #1570 -// pretty-expanded FIXME #23616 pub fn main() { test_misc(); diff --git a/src/test/run-pass/signal-exit-status.rs b/src/test/run-pass/signal-exit-status.rs index bfc4aee775..51b369092f 100644 --- a/src/test/run-pass/signal-exit-status.rs +++ b/src/test/run-pass/signal-exit-status.rs @@ -10,11 +10,8 @@ // ignore-windows -#![feature(old_io)] -#![feature(os)] - use std::env; -use std::old_io::process::{Command, ExitSignal, ExitStatus}; +use std::process::Command; pub fn main() { let args: Vec = env::args().collect(); @@ -23,11 +20,6 @@ pub fn main() { unsafe { *(0 as *mut isize) = 0; } } else { let status = Command::new(&args[0]).arg("signal").status().unwrap(); - // Windows does not have signal, so we get exit status 0xC0000028 (STATUS_BAD_STACK). - match status { - ExitSignal(_) if cfg!(unix) => {}, - ExitStatus(0xC0000028) if cfg!(windows) => {}, - _ => panic!("invalid termination (was not signalled): {}", status) - } + assert!(status.code().is_none()); } } diff --git a/src/test/run-pass/signed-shift-const-eval.rs b/src/test/run-pass/signed-shift-const-eval.rs index 7167236438..9ea2dedcba 100644 --- a/src/test/run-pass/signed-shift-const-eval.rs +++ b/src/test/run-pass/signed-shift-const-eval.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum test { thing = -5 >> 1_usize } pub fn main() { diff --git a/src/test/run-pass/sigpipe-should-be-ignored.rs b/src/test/run-pass/sigpipe-should-be-ignored.rs index 4a05b487ae..7734a2e80c 100644 --- a/src/test/run-pass/sigpipe-should-be-ignored.rs +++ b/src/test/run-pass/sigpipe-should-be-ignored.rs @@ -12,7 +12,6 @@ // doesn't die in a ball of fire, but rather it's gracefully handled. // ignore-aarch64 -// pretty-expanded FIXME #23616 use std::env; use std::io::prelude::*; diff --git a/src/test/run-pass/simd-binop.rs b/src/test/run-pass/simd-binop.rs index 9f7b78e4e3..3ebf2a8736 100644 --- a/src/test/run-pass/simd-binop.rs +++ b/src/test/run-pass/simd-binop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 867f028a3f..0e3d6b83a4 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(simd)] diff --git a/src/test/run-pass/simd-size-align.rs b/src/test/run-pass/simd-size-align.rs index 8324efc641..025b2a7737 100644 --- a/src/test/run-pass/simd-size-align.rs +++ b/src/test/run-pass/simd-size-align.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(simd)] #![allow(non_camel_case_types)] diff --git a/src/test/run-pass/slice-2.rs b/src/test/run-pass/slice-2.rs index 7f34b94ad0..4762470a74 100644 --- a/src/test/run-pass/slice-2.rs +++ b/src/test/run-pass/slice-2.rs @@ -10,7 +10,6 @@ // Test slicing expressions on slices and Vecs. -// pretty-expanded FIXME #23616 fn main() { let x: &[isize] = &[1, 2, 3, 4, 5]; diff --git a/src/test/run-pass/slice-panic-1.rs b/src/test/run-pass/slice-panic-1.rs index a4f737f746..854b03f917 100644 --- a/src/test/run-pass/slice-panic-1.rs +++ b/src/test/run-pass/slice-panic-1.rs @@ -10,7 +10,6 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/slice-panic-2.rs b/src/test/run-pass/slice-panic-2.rs index f02a84b907..42a1934288 100644 --- a/src/test/run-pass/slice-panic-2.rs +++ b/src/test/run-pass/slice-panic-2.rs @@ -10,7 +10,6 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/slice.rs b/src/test/run-pass/slice.rs index edc5f6b184..60160bd668 100644 --- a/src/test/run-pass/slice.rs +++ b/src/test/run-pass/slice.rs @@ -10,7 +10,6 @@ // Test slicing sugar. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/small-enum-range-edge.rs b/src/test/run-pass/small-enum-range-edge.rs index 9515da6fcb..56abdf6e20 100644 --- a/src/test/run-pass/small-enum-range-edge.rs +++ b/src/test/run-pass/small-enum-range-edge.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 // this is for the wrapping_add call below. #![feature(core)] diff --git a/src/test/run-pass/spawn-fn.rs b/src/test/run-pass/spawn-fn.rs index efddf0455c..4a35ed609e 100644 --- a/src/test/run-pass/spawn-fn.rs +++ b/src/test/run-pass/spawn-fn.rs @@ -16,13 +16,16 @@ fn x(s: String, n: isize) { } pub fn main() { - let _t = thread::scoped(|| x("hello from first spawned fn".to_string(), 65) ); - let _t = thread::scoped(|| x("hello from second spawned fn".to_string(), 66) ); - let _t = thread::scoped(|| x("hello from third spawned fn".to_string(), 67) ); + let t1 = thread::spawn(|| x("hello from first spawned fn".to_string(), 65) ); + let t2 = thread::spawn(|| x("hello from second spawned fn".to_string(), 66) ); + let t3 = thread::spawn(|| x("hello from third spawned fn".to_string(), 67) ); let mut i = 30; while i > 0 { i = i - 1; println!("parent sleeping"); thread::yield_now(); } + t1.join(); + t2.join(); + t3.join(); } diff --git a/src/test/run-pass/spawn-types.rs b/src/test/run-pass/spawn-types.rs index aab292a940..ae4fabd34d 100644 --- a/src/test/run-pass/spawn-types.rs +++ b/src/test/run-pass/spawn-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 /* Make sure we can spawn tasks that take different types of diff --git a/src/test/run-pass/stable-addr-of.rs b/src/test/run-pass/stable-addr-of.rs index f93600195d..5ffceb2c6a 100644 --- a/src/test/run-pass/stable-addr-of.rs +++ b/src/test/run-pass/stable-addr-of.rs @@ -10,7 +10,6 @@ // Issue #2040 -// pretty-expanded FIXME #23616 pub fn main() { let foo: isize = 1; diff --git a/src/test/run-pass/static-function-pointer-xc.rs b/src/test/run-pass/static-function-pointer-xc.rs index 55f3b0883b..a09928bd22 100644 --- a/src/test/run-pass/static-function-pointer-xc.rs +++ b/src/test/run-pass/static-function-pointer-xc.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:static-function-pointer-aux.rs -// pretty-expanded FIXME #23616 extern crate static_function_pointer_aux as aux; diff --git a/src/test/run-pass/static-function-pointer.rs b/src/test/run-pass/static-function-pointer.rs index 67cc033f7c..be29752430 100644 --- a/src/test/run-pass/static-function-pointer.rs +++ b/src/test/run-pass/static-function-pointer.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: isize) -> isize { x } fn g(x: isize) -> isize { 2 * x } diff --git a/src/test/run-pass/static-impl.rs b/src/test/run-pass/static-impl.rs index aff2797c1a..84bb1b871b 100644 --- a/src/test/run-pass/static-impl.rs +++ b/src/test/run-pass/static-impl.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 pub trait plus { fn plus(&self) -> isize; diff --git a/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs index 4ccb044bbd..c2b3a9a722 100644 --- a/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs +++ b/src/test/run-pass/static-method-in-trait-with-tps-intracrate.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Deserializer { fn read_int(&self) -> isize; diff --git a/src/test/run-pass/static-method-xcrate.rs b/src/test/run-pass/static-method-xcrate.rs index d0b69b430a..57609cec9f 100644 --- a/src/test/run-pass/static-method-xcrate.rs +++ b/src/test/run-pass/static-method-xcrate.rs @@ -10,7 +10,6 @@ // aux-build:static-methods-crate.rs -// pretty-expanded FIXME #23616 extern crate static_methods_crate; diff --git a/src/test/run-pass/static-methods-in-traits.rs b/src/test/run-pass/static-methods-in-traits.rs index cb23feb05a..3fd3bbe936 100644 --- a/src/test/run-pass/static-methods-in-traits.rs +++ b/src/test/run-pass/static-methods-in-traits.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod a { pub trait Foo { diff --git a/src/test/run-pass/static-mut-foreign.rs b/src/test/run-pass/static-mut-foreign.rs index c6b919c973..b916a1ae2b 100644 --- a/src/test/run-pass/static-mut-foreign.rs +++ b/src/test/run-pass/static-mut-foreign.rs @@ -12,7 +12,6 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. -// pretty-expanded FIXME #23616 #![feature(libc)] diff --git a/src/test/run-pass/static-mut-xc.rs b/src/test/run-pass/static-mut-xc.rs index 0456d17bdc..c819db9454 100644 --- a/src/test/run-pass/static-mut-xc.rs +++ b/src/test/run-pass/static-mut-xc.rs @@ -14,7 +14,6 @@ // aux-build:static_mut_xc.rs -// pretty-expanded FIXME #23616 extern crate static_mut_xc; diff --git a/src/test/run-pass/str-multiline.rs b/src/test/run-pass/str-multiline.rs index 0d0d56fcaf..94e1429049 100644 --- a/src/test/run-pass/str-multiline.rs +++ b/src/test/run-pass/str-multiline.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let a: String = "this \ diff --git a/src/test/run-pass/string-escapes.rs b/src/test/run-pass/string-escapes.rs index e0fc1c4ce4..1d13e53100 100644 --- a/src/test/run-pass/string-escapes.rs +++ b/src/test/run-pass/string-escapes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn main() { let x = "\\\\\ diff --git a/src/test/run-pass/struct-aliases-xcrate.rs b/src/test/run-pass/struct-aliases-xcrate.rs index 17cb8acea6..2ca9d599d8 100644 --- a/src/test/run-pass/struct-aliases-xcrate.rs +++ b/src/test/run-pass/struct-aliases-xcrate.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:xcrate_struct_aliases.rs -// pretty-expanded FIXME #23616 extern crate xcrate_struct_aliases; diff --git a/src/test/run-pass/struct-aliases.rs b/src/test/run-pass/struct-aliases.rs index 79e7960cfb..7107243d76 100644 --- a/src/test/run-pass/struct-aliases.rs +++ b/src/test/run-pass/struct-aliases.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { x: isize, diff --git a/src/test/run-pass/struct-destructuring-cross-crate.rs b/src/test/run-pass/struct-destructuring-cross-crate.rs index 5fed712bd6..63e8d694dd 100644 --- a/src/test/run-pass/struct-destructuring-cross-crate.rs +++ b/src/test/run-pass/struct-destructuring-cross-crate.rs @@ -10,7 +10,6 @@ // aux-build:struct_destructuring_cross_crate.rs -// pretty-expanded FIXME #23616 extern crate struct_destructuring_cross_crate; diff --git a/src/test/run-pass/struct-like-variant-match.rs b/src/test/run-pass/struct-like-variant-match.rs index f072d315d7..175090eadd 100644 --- a/src/test/run-pass/struct-like-variant-match.rs +++ b/src/test/run-pass/struct-like-variant-match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum Foo { Bar { diff --git a/src/test/run-pass/struct-new-as-field-name.rs b/src/test/run-pass/struct-new-as-field-name.rs index 73f27448f8..7fb3a64e02 100644 --- a/src/test/run-pass/struct-new-as-field-name.rs +++ b/src/test/run-pass/struct-new-as-field-name.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo { new: isize, diff --git a/src/test/run-pass/struct-order-of-eval-1.rs b/src/test/run-pass/struct-order-of-eval-1.rs index 49ec695a12..b5e4011bbe 100644 --- a/src/test/run-pass/struct-order-of-eval-1.rs +++ b/src/test/run-pass/struct-order-of-eval-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { f0: String, f1: isize } diff --git a/src/test/run-pass/struct-order-of-eval-2.rs b/src/test/run-pass/struct-order-of-eval-2.rs index 45755608ff..7ec28f597e 100644 --- a/src/test/run-pass/struct-order-of-eval-2.rs +++ b/src/test/run-pass/struct-order-of-eval-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct S { f0: String, diff --git a/src/test/run-pass/struct-order-of-eval-3.rs b/src/test/run-pass/struct-order-of-eval-3.rs index 37b6de8e17..60f9c4465a 100644 --- a/src/test/run-pass/struct-order-of-eval-3.rs +++ b/src/test/run-pass/struct-order-of-eval-3.rs @@ -11,7 +11,6 @@ // Checks that functional-record-update order-of-eval is as expected // even when no Drop-implementations are involved. -// pretty-expanded FIXME #23616 use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/struct-order-of-eval-4.rs b/src/test/run-pass/struct-order-of-eval-4.rs index 1b53895f7d..23a7e1ea71 100644 --- a/src/test/run-pass/struct-order-of-eval-4.rs +++ b/src/test/run-pass/struct-order-of-eval-4.rs @@ -11,7 +11,6 @@ // Checks that struct-literal expression order-of-eval is as expected // even when no Drop-implementations are involved. -// pretty-expanded FIXME #23616 use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; diff --git a/src/test/run-pass/struct_variant_xc_match.rs b/src/test/run-pass/struct_variant_xc_match.rs index f43dd2332a..3ceb65bcfd 100644 --- a/src/test/run-pass/struct_variant_xc_match.rs +++ b/src/test/run-pass/struct_variant_xc_match.rs @@ -9,7 +9,6 @@ // except according to those terms. // aux-build:struct_variant_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate struct_variant_xc_aux; diff --git a/src/test/run-pass/supertrait-default-generics.rs b/src/test/run-pass/supertrait-default-generics.rs index 351c4259b5..e014ce1966 100644 --- a/src/test/run-pass/supertrait-default-generics.rs +++ b/src/test/run-pass/supertrait-default-generics.rs @@ -10,7 +10,6 @@ // There is some other borrowck bug, so we make the stuff not mut. -// pretty-expanded FIXME #23616 use std::ops::Add; diff --git a/src/test/run-pass/swap-1.rs b/src/test/run-pass/swap-1.rs index e60c672f00..d84ee10451 100644 --- a/src/test/run-pass/swap-1.rs +++ b/src/test/run-pass/swap-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/swap-2.rs b/src/test/run-pass/swap-2.rs index 3891376e46..3dbd7f1a60 100644 --- a/src/test/run-pass/swap-2.rs +++ b/src/test/run-pass/swap-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::swap; diff --git a/src/test/run-pass/syntax-extension-cfg.rs b/src/test/run-pass/syntax-extension-cfg.rs index 8766cba5db..c1d8713b20 100644 --- a/src/test/run-pass/syntax-extension-cfg.rs +++ b/src/test/run-pass/syntax-extension-cfg.rs @@ -10,7 +10,6 @@ // compile-flags: --cfg foo --cfg qux="foo" -// pretty-expanded FIXME #23616 pub fn main() { // check diff --git a/src/test/run-pass/syntax-trait-polarity.rs b/src/test/run-pass/syntax-trait-polarity.rs index ba8a3f77aa..f69b857981 100644 --- a/src/test/run-pass/syntax-trait-polarity.rs +++ b/src/test/run-pass/syntax-trait-polarity.rs @@ -10,15 +10,13 @@ // pretty-expanded FIXME #23616 -#![feature(optin_builtin_traits, core)] - -use std::marker::{MarkerTrait, Send}; +#![feature(optin_builtin_traits)] struct TestType; impl TestType {} -trait TestTrait : MarkerTrait {} +trait TestTrait {} impl !Send for TestType {} diff --git a/src/test/run-pass/tag-align-dyn-u64.rs b/src/test/run-pass/tag-align-dyn-u64.rs index a9f5875023..aaac1869af 100644 --- a/src/test/run-pass/tag-align-dyn-u64.rs +++ b/src/test/run-pass/tag-align-dyn-u64.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index 90b583e2e5..1c3fb209e3 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index e922ac3b46..43485a5bfc 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index a063801032..6dc6965675 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use color::{red, green, blue, black, white, imaginary, purple, orange}; diff --git a/src/test/run-pass/tag.rs b/src/test/run-pass/tag.rs index dbd65ee6bd..e3cfceb0d4 100644 --- a/src/test/run-pass/tag.rs +++ b/src/test/run-pass/tag.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 enum colour { red(isize, isize), green, } diff --git a/src/test/run-pass/tail-direct.rs b/src/test/run-pass/tail-direct.rs index 01fc18af34..4a7a0acdfa 100644 --- a/src/test/run-pass/tail-direct.rs +++ b/src/test/run-pass/tail-direct.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { assert!((even(42))); assert!((odd(45))); } diff --git a/src/test/run-pass/task-comm-0.rs b/src/test/run-pass/task-comm-0.rs index 786dd2c761..1409caf9c7 100644 --- a/src/test/run-pass/task-comm-0.rs +++ b/src/test/run-pass/task-comm-0.rs @@ -26,7 +26,7 @@ fn test05_start(tx : &Sender) { fn test05() { let (tx, rx) = channel(); - let _t = thread::scoped(move|| { test05_start(&tx) }); + let t = thread::spawn(move|| { test05_start(&tx) }); let mut value: isize = rx.recv().unwrap(); println!("{}", value); value = rx.recv().unwrap(); @@ -34,4 +34,5 @@ fn test05() { value = rx.recv().unwrap(); println!("{}", value); assert_eq!(value, 30); + t.join(); } diff --git a/src/test/run-pass/task-comm-1.rs b/src/test/run-pass/task-comm-1.rs index 9c3466f162..b3327d82c3 100644 --- a/src/test/run-pass/task-comm-1.rs +++ b/src/test/run-pass/task-comm-1.rs @@ -17,6 +17,6 @@ pub fn main() { test00(); } fn start() { println!("Started / Finished task."); } fn test00() { - let _ = thread::scoped(move|| start() ).join(); + thread::spawn(move|| start() ).join(); println!("Completing."); } diff --git a/src/test/run-pass/task-comm-10.rs b/src/test/run-pass/task-comm-10.rs index f25bb3ff71..a796750ef8 100644 --- a/src/test/run-pass/task-comm-10.rs +++ b/src/test/run-pass/task-comm-10.rs @@ -29,10 +29,12 @@ fn start(tx: &Sender>) { pub fn main() { let (tx, rx) = channel(); - let _child = thread::scoped(move|| { start(&tx) }); + let child = thread::spawn(move|| { start(&tx) }); let mut c = rx.recv().unwrap(); c.send("A".to_string()).unwrap(); c.send("B".to_string()).unwrap(); thread::yield_now(); + + child.join(); } diff --git a/src/test/run-pass/task-comm-11.rs b/src/test/run-pass/task-comm-11.rs index ec9ed53c1d..7af8f5d3b3 100644 --- a/src/test/run-pass/task-comm-11.rs +++ b/src/test/run-pass/task-comm-11.rs @@ -22,8 +22,9 @@ fn start(tx: &Sender>) { pub fn main() { let (tx, rx) = channel(); - let _child = thread::scoped(move|| { + let child = thread::spawn(move|| { start(&tx) }); let _tx = rx.recv().unwrap(); + child.join(); } diff --git a/src/test/run-pass/task-comm-12.rs b/src/test/run-pass/task-comm-12.rs index 03305091a2..f8d608d316 100644 --- a/src/test/run-pass/task-comm-12.rs +++ b/src/test/run-pass/task-comm-12.rs @@ -18,7 +18,7 @@ fn start(_task_number: isize) { println!("Started / Finished task."); } fn test00() { let i: isize = 0; - let mut result = thread::scoped(move|| { + let mut result = thread::spawn(move|| { start(i) }); diff --git a/src/test/run-pass/task-comm-13.rs b/src/test/run-pass/task-comm-13.rs index 15ceacd672..156ddd9c77 100644 --- a/src/test/run-pass/task-comm-13.rs +++ b/src/test/run-pass/task-comm-13.rs @@ -21,6 +21,6 @@ fn start(tx: &Sender, start: isize, number_of_messages: isize) { pub fn main() { println!("Check that we don't deadlock."); let (tx, rx) = channel(); - let _t = thread::scoped(move|| { start(&tx, 0, 10) }).join(); + let _ = thread::spawn(move|| { start(&tx, 0, 10) }).join(); println!("Joined task"); } diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs index 1e2d9fe52d..0048d7d2d7 100644 --- a/src/test/run-pass/task-comm-14.rs +++ b/src/test/run-pass/task-comm-14.rs @@ -21,7 +21,7 @@ pub fn main() { while (i > 0) { println!("{}", i); let tx = tx.clone(); - thread::scoped({let i = i; move|| { child(i, &tx) }}); + thread::spawn({let i = i; move|| { child(i, &tx) }}); i = i - 1; } diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs index 2663595aec..1d853b3e67 100644 --- a/src/test/run-pass/task-comm-15.rs +++ b/src/test/run-pass/task-comm-15.rs @@ -29,8 +29,9 @@ pub fn main() { // the child's point of view the receiver may die. We should // drop messages on the floor in this case, and not crash! let (tx, rx) = channel(); - let _t = thread::scoped(move|| { + let t = thread::spawn(move|| { start(&tx, 10) }); rx.recv(); + t.join(); } diff --git a/src/test/run-pass/task-comm-17.rs b/src/test/run-pass/task-comm-17.rs index de334c77aa..8f6f971ce3 100644 --- a/src/test/run-pass/task-comm-17.rs +++ b/src/test/run-pass/task-comm-17.rs @@ -22,5 +22,5 @@ fn f() { } pub fn main() { - let _t = thread::scoped(move|| f() ).join(); + thread::spawn(move|| f() ).join(); } diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 254ad653c4..25f40757b7 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -42,7 +42,7 @@ fn test00() { let mut results = Vec::new(); while i < number_of_tasks { let tx = tx.clone(); - results.push(thread::scoped({ + results.push(thread::spawn({ let i = i; move|| { test00_start(&tx, i, number_of_messages) diff --git a/src/test/run-pass/task-comm-5.rs b/src/test/run-pass/task-comm-5.rs index cd3d97b88b..cd5cb677d4 100644 --- a/src/test/run-pass/task-comm-5.rs +++ b/src/test/run-pass/task-comm-5.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; diff --git a/src/test/run-pass/task-comm-6.rs b/src/test/run-pass/task-comm-6.rs index 80e777d242..b8b5773ade 100644 --- a/src/test/run-pass/task-comm-6.rs +++ b/src/test/run-pass/task-comm-6.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs index b05e36552a..e37160f979 100644 --- a/src/test/run-pass/task-comm-7.rs +++ b/src/test/run-pass/task-comm-7.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc)] #![allow(dead_assignment)] @@ -31,19 +30,19 @@ fn test00() { let number_of_messages: isize = 10; let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t1 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 0, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t2 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 1, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t3 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 2, number_of_messages); }); let tx2 = tx.clone(); - let _t = thread::scoped(move|| { + let t4 = thread::spawn(move|| { test00_start(&tx2, number_of_messages * 3, number_of_messages); }); @@ -61,4 +60,9 @@ fn test00() { } assert_eq!(sum, number_of_messages * 4 * (number_of_messages * 4 - 1) / 2); + + t1.join(); + t2.join(); + t3.join(); + t4.join(); } diff --git a/src/test/run-pass/task-comm-9.rs b/src/test/run-pass/task-comm-9.rs index 758764aa9f..d8eec4169e 100644 --- a/src/test/run-pass/task-comm-9.rs +++ b/src/test/run-pass/task-comm-9.rs @@ -26,7 +26,7 @@ fn test00() { let (tx, rx) = channel(); let number_of_messages: isize = 10; - let result = thread::scoped(move|| { + let result = thread::spawn(move|| { test00_start(&tx, number_of_messages); }); diff --git a/src/test/run-pass/task-comm-chan-nil.rs b/src/test/run-pass/task-comm-chan-nil.rs index 77571504fe..3b9ec42169 100644 --- a/src/test/run-pass/task-comm-chan-nil.rs +++ b/src/test/run-pass/task-comm-chan-nil.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::mpsc::channel; diff --git a/src/test/run-pass/task-life-0.rs b/src/test/run-pass/task-life-0.rs index b97f4355b3..ba8819fd0b 100644 --- a/src/test/run-pass/task-life-0.rs +++ b/src/test/run-pass/task-life-0.rs @@ -15,7 +15,7 @@ use std::thread; pub fn main() { - let _t = thread::scoped(move|| child("Hello".to_string()) ); + thread::spawn(move|| child("Hello".to_string()) ).join(); } fn child(_s: String) { diff --git a/src/test/run-pass/task-spawn-move-and-copy.rs b/src/test/run-pass/task-spawn-move-and-copy.rs index aa7b61bf11..6a84ec47c9 100644 --- a/src/test/run-pass/task-spawn-move-and-copy.rs +++ b/src/test/run-pass/task-spawn-move-and-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc)] @@ -22,11 +21,13 @@ pub fn main() { let x: Box = box 1; let x_in_parent = &(*x) as *const isize as usize; - let _t = thread::scoped(move || { + let t = thread::spawn(move || { let x_in_child = &(*x) as *const isize as usize; tx.send(x_in_child).unwrap(); }); let x_in_child = rx.recv().unwrap(); assert_eq!(x_in_parent, x_in_child); + + t.join(); } diff --git a/src/test/run-pass/task-stderr.rs b/src/test/run-pass/task-stderr.rs index 7bcde7b83c..4a1bb5a591 100644 --- a/src/test/run-pass/task-stderr.rs +++ b/src/test/run-pass/task-stderr.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - -#![allow(unknown_features)] -#![feature(box_syntax, old_io, std_misc, io, set_panic, set_stdio)] +#![feature(box_syntax, set_stdio)] use std::io::prelude::*; use std::io; diff --git a/src/test/run-pass/tcp-accept-stress.rs b/src/test/run-pass/tcp-accept-stress.rs deleted file mode 100644 index 00467e5633..0000000000 --- a/src/test/run-pass/tcp-accept-stress.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2014 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. - -// ignore-macos osx really doesn't like cycling through large numbers of -// sockets as calls to connect() will start returning EADDRNOTAVAIL -// quite quickly and it takes a few seconds for the sockets to get -// recycled. - -#![feature(old_io, io, std_misc)] - -use std::old_io::{TcpListener, Listener, Acceptor, EndOfFile, TcpStream}; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc::channel; -use std::thread; - -static N: usize = 8; -static M: usize = 20; - -fn main() { - test(); -} - -fn test() { - let mut l = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = l.socket_name().unwrap(); - let mut a = l.listen().unwrap(); - let cnt = Arc::new(AtomicUsize::new(0)); - - let (srv_tx, srv_rx) = channel(); - let (cli_tx, cli_rx) = channel(); - let _t = (0..N).map(|_| { - let a = a.clone(); - let cnt = cnt.clone(); - let srv_tx = srv_tx.clone(); - thread::scoped(move|| { - let mut a = a; - loop { - match a.accept() { - Ok(..) => { - if cnt.fetch_add(1, Ordering::SeqCst) == N * M - 1 { - break - } - } - Err(ref e) if e.kind == EndOfFile => break, - Err(e) => panic!("{}", e), - } - } - srv_tx.send(()); - }) - }).collect::>(); - - let _t = (0..N).map(|_| { - let cli_tx = cli_tx.clone(); - thread::scoped(move|| { - for _ in 0..M { - let _s = TcpStream::connect(addr).unwrap(); - } - cli_tx.send(()); - }) - }).collect::>(); - drop((cli_tx, srv_tx)); - - // wait for senders - if cli_rx.iter().take(N).count() != N { - a.close_accept().unwrap(); - panic!("clients panicked"); - } - - // wait for one acceptor to die - let _ = srv_rx.recv(); - - // Notify other receivers should die - a.close_accept().unwrap(); - - // wait for receivers - assert_eq!(srv_rx.iter().take(N - 1).count(), N - 1); - - // Everything should have been accepted. - assert_eq!(cnt.load(Ordering::SeqCst), N * M); -} diff --git a/src/test/run-pass/tcp-connect-timeouts.rs b/src/test/run-pass/tcp-connect-timeouts.rs deleted file mode 100644 index 64f07a60b3..0000000000 --- a/src/test/run-pass/tcp-connect-timeouts.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2014 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. - -// ignore-pretty -// compile-flags:--test -// exec-env:RUST_TEST_THREADS=1 - -// Tests for the connect_timeout() function on a TcpStream. This runs with only -// one test task to ensure that errors are timeouts, not file descriptor -// exhaustion. - -#![reexport_test_harness_main = "test_main"] - -#![allow(unused_imports)] -#![feature(old_io, std_misc, io)] - -use std::old_io::*; -use std::old_io::test::*; -use std::old_io; -use std::time::Duration; -use std::sync::mpsc::channel; -use std::thread; - -#[cfg_attr(target_os = "freebsd", ignore)] -fn eventual_timeout() { - let addr = next_test_ip4(); - - let (tx1, rx1) = channel(); - let (_tx2, rx2) = channel::<()>(); - let _t = thread::scoped(move|| { - let _l = TcpListener::bind(addr).unwrap().listen(); - tx1.send(()).unwrap(); - let _ = rx2.recv(); - }); - rx1.recv().unwrap(); - - let mut v = Vec::new(); - for _ in 0_usize..10000 { - match TcpStream::connect_timeout(addr, Duration::milliseconds(100)) { - Ok(e) => v.push(e), - Err(ref e) if e.kind == old_io::TimedOut => return, - Err(e) => panic!("other error: {}", e), - } - } - panic!("never timed out!"); -} - -fn timeout_success() { - let addr = next_test_ip4(); - let _l = TcpListener::bind(addr).unwrap().listen(); - - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_ok()); -} - -fn timeout_error() { - let addr = next_test_ip4(); - - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(1000)).is_err()); -} - -fn connect_timeout_zero() { - let addr = next_test_ip4(); - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(0)).is_err()); -} - -fn connect_timeout_negative() { - let addr = next_test_ip4(); - assert!(TcpStream::connect_timeout(addr, Duration::milliseconds(-1)).is_err()); -} diff --git a/src/test/run-pass/tcp-stress.rs b/src/test/run-pass/tcp-stress.rs index 4209d5986b..c47b95bec2 100644 --- a/src/test/run-pass/tcp-stress.rs +++ b/src/test/run-pass/tcp-stress.rs @@ -8,64 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-linux see joyent/libuv#1189 // ignore-android needs extra network permissions // ignore-openbsd system ulimit (Too many open files) -// exec-env:RUST_LOG=debug - -#![feature(rustc_private, libc, old_io, io, std_misc)] -#![allow(deprecated, unused_must_use)] - -#[macro_use] -extern crate log; -extern crate libc; +// ignore-bitrig system ulimit (Too many open files) +use std::io::prelude::*; +use std::net::{TcpListener, TcpStream}; +use std::process; use std::sync::mpsc::channel; -use std::old_io::net::tcp::{TcpListener, TcpStream}; -use std::old_io::{Acceptor, Listener, Reader, Writer}; use std::thread::{self, Builder}; -use std::time::Duration; fn main() { // This test has a chance to time out, try to not let it time out thread::spawn(move|| -> () { - use std::old_io::timer; - timer::sleep(Duration::milliseconds(30 * 1000)); - println!("timed out!"); - unsafe { libc::exit(1) } + thread::sleep_ms(30 * 1000); + process::exit(1); }); - let (tx, rx) = channel(); + let mut listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); thread::spawn(move || -> () { - let mut listener = TcpListener::bind("127.0.0.1:0").unwrap(); - tx.send(listener.socket_name().unwrap()).unwrap(); - let mut acceptor = listener.listen(); loop { - let mut stream = match acceptor.accept() { - Ok(stream) => stream, - Err(error) => { - debug!("accept panicked: {}", error); - continue; - } + let mut stream = match listener.accept() { + Ok(stream) => stream.0, + Err(error) => continue, }; - stream.read_byte(); + stream.read(&mut [0]); stream.write(&[2]); } }); - let addr = rx.recv().unwrap(); let (tx, rx) = channel(); for _ in 0..1000 { let tx = tx.clone(); Builder::new().stack_size(64 * 1024).spawn(move|| { match TcpStream::connect(addr) { - Ok(stream) => { - let mut stream = stream; + Ok(mut stream) => { stream.write(&[1]); - let mut buf = [0]; - stream.read(&mut buf); + stream.read(&mut [0]); }, - Err(e) => debug!("{}", e) + Err(..) => {} } tx.send(()).unwrap(); }); @@ -77,5 +59,5 @@ fn main() { for _ in 0..1000 { rx.recv().unwrap(); } - unsafe { libc::exit(0) } + process::exit(0); } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs deleted file mode 100644 index 49fac24d0b..0000000000 --- a/src/test/run-pass/tempfile.rs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2013-2014 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. - -// ignore-windows TempDir may cause IoError on windows: #10463 - -// These tests are here to exercise the functionality of the `tempfile` module. -// One might expect these tests to be located in that module, but sadly they -// cannot. The tests need to invoke `os::change_dir` which cannot be done in the -// normal test infrastructure. If the tests change the current working -// directory, then *all* tests which require relative paths suddenly break b/c -// they're in a different location than before. Hence, these tests are all run -// serially here. - -#![feature(old_io, old_path, os, old_fs)] - -use std::old_path::{Path, GenericPath}; -use std::old_io::fs::PathExtensions; -use std::old_io::{fs, TempDir}; -use std::old_io; -use std::env; -use std::sync::mpsc::channel; -use std::thread; - -fn test_tempdir() { - let path = { - let p = TempDir::new_in(&Path::new("."), "foobar").unwrap(); - let p = p.path(); - assert!(p.as_str().unwrap().contains("foobar")); - p.clone() - }; - assert!(!path.exists()); -} - -fn test_rm_tempdir() { - let (tx, rx) = channel(); - let f = move|| -> () { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - tx.send(tmp.path().clone()).unwrap(); - panic!("panic to unwind past `tmp`"); - }; - thread::spawn(f).join(); - let path = rx.recv().unwrap(); - assert!(!path.exists()); - - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - let path = tmp.path().clone(); - let f = move|| -> () { - let _tmp = tmp; - panic!("panic to unwind past `tmp`"); - }; - thread::spawn(f).join(); - assert!(!path.exists()); - - let path; - { - let f = move || { - TempDir::new("test_rm_tempdir").unwrap() - }; - // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = thread::scoped(f).join(); - path = tmp.path().clone(); - assert!(path.exists()); - } - assert!(!path.exists()); - - let path; - { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - path = tmp.into_inner(); - } - assert!(path.exists()); - fs::rmdir_recursive(&path); - assert!(!path.exists()); -} - -fn test_rm_tempdir_close() { - let (tx, rx) = channel(); - let f = move|| -> () { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - tx.send(tmp.path().clone()).unwrap(); - tmp.close(); - panic!("panic when unwinding past `tmp`"); - }; - thread::spawn(f).join(); - let path = rx.recv().unwrap(); - assert!(!path.exists()); - - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - let path = tmp.path().clone(); - let f = move|| -> () { - let tmp = tmp; - tmp.close(); - panic!("panic when unwinding past `tmp`"); - }; - thread::spawn(f).join(); - assert!(!path.exists()); - - let path; - { - let f = move || { - TempDir::new("test_rm_tempdir").unwrap() - }; - // FIXME(#16640) `: TempDir` annotation shouldn't be necessary - let tmp: TempDir = thread::scoped(f).join(); - path = tmp.path().clone(); - assert!(path.exists()); - tmp.close(); - } - assert!(!path.exists()); - - let path; - { - let tmp = TempDir::new("test_rm_tempdir").unwrap(); - path = tmp.into_inner(); - } - assert!(path.exists()); - fs::rmdir_recursive(&path); - assert!(!path.exists()); -} - -// Ideally these would be in std::os but then core would need -// to depend on std -fn recursive_mkdir_rel() { - let path = Path::new("frob"); - let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap()); - println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(), - cwd.display(), path.exists()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); -} - -fn recursive_mkdir_dot() { - let dot = Path::new("."); - fs::mkdir_recursive(&dot, old_io::USER_RWX); - let dotdot = Path::new(".."); - fs::mkdir_recursive(&dotdot, old_io::USER_RWX); -} - -fn recursive_mkdir_rel_2() { - let path = Path::new("./frob/baz"); - let cwd = Path::new(env::current_dir().unwrap().to_str().unwrap()); - println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(), - cwd.display(), path.exists()); - fs::mkdir_recursive(&path, old_io::USER_RWX); - assert!(path.is_dir()); - assert!(path.dir_path().is_dir()); - let path2 = Path::new("quux/blat"); - println!("recursive_mkdir_rel_2: Making: {} in cwd {}", path2.display(), - cwd.display()); - fs::mkdir_recursive(&path2, old_io::USER_RWX); - assert!(path2.is_dir()); - assert!(path2.dir_path().is_dir()); -} - -// Ideally this would be in core, but needs TempFile -pub fn test_rmdir_recursive_ok() { - let rwx = old_io::USER_RWX; - - let tmpdir = TempDir::new("test").ok().expect("test_rmdir_recursive_ok: \ - couldn't create temp dir"); - let tmpdir = tmpdir.path(); - let root = tmpdir.join("foo"); - - println!("making {}", root.display()); - fs::mkdir(&root, rwx); - fs::mkdir(&root.join("foo"), rwx); - fs::mkdir(&root.join("foo").join("bar"), rwx); - fs::mkdir(&root.join("foo").join("bar").join("blat"), rwx); - fs::rmdir_recursive(&root); - assert!(!root.exists()); - assert!(!root.join("bar").exists()); - assert!(!root.join("bar").join("blat").exists()); -} - -pub fn dont_double_panic() { - let r: Result<(), _> = thread::spawn(move|| { - let tmpdir = TempDir::new("test").unwrap(); - // Remove the temporary directory so that TempDir sees - // an error on drop - fs::rmdir(tmpdir.path()); - // Panic. If TempDir panics *again* due to the rmdir - // error then the process will abort. - panic!(); - }).join(); - assert!(r.is_err()); -} - -fn in_tmpdir(f: F) where F: FnOnce() { - let tmpdir = TempDir::new("test").ok().expect("can't make tmpdir"); - assert!(env::set_current_dir(tmpdir.path().as_str().unwrap()).is_ok()); - - f(); -} - -pub fn main() { - in_tmpdir(test_tempdir); - in_tmpdir(test_rm_tempdir); - in_tmpdir(test_rm_tempdir_close); - in_tmpdir(recursive_mkdir_rel); - in_tmpdir(recursive_mkdir_dot); - in_tmpdir(recursive_mkdir_rel_2); - in_tmpdir(test_rmdir_recursive_ok); - in_tmpdir(dont_double_panic); -} diff --git a/src/test/run-pass/terminate-in-initializer.rs b/src/test/run-pass/terminate-in-initializer.rs index ec9e7de40d..83eb351df5 100644 --- a/src/test/run-pass/terminate-in-initializer.rs +++ b/src/test/run-pass/terminate-in-initializer.rs @@ -12,7 +12,6 @@ // Issue #787 // Don't try to clean up uninitialized locals -// pretty-expanded FIXME #23616 use std::thread; diff --git a/src/test/run-pass/threads.rs b/src/test/run-pass/threads.rs index 969a42a6f8..184338c329 100644 --- a/src/test/run-pass/threads.rs +++ b/src/test/run-pass/threads.rs @@ -15,7 +15,7 @@ use std::thread; pub fn main() { let mut i = 10; while i > 0 { - thread::scoped({let i = i; move|| child(i)}); + thread::spawn({let i = i; move|| child(i)}).join(); i = i - 1; } println!("main thread exiting"); diff --git a/src/test/run-pass/trait-bounds-basic.rs b/src/test/run-pass/trait-bounds-basic.rs index 50c9c43ba2..558e69664e 100644 --- a/src/test/run-pass/trait-bounds-basic.rs +++ b/src/test/run-pass/trait-bounds-basic.rs @@ -10,9 +10,7 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -trait Foo : ::std::marker::MarkerTrait { +trait Foo { } fn b(_x: Box) { diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 02ea703705..21205a2d7f 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -83,16 +83,19 @@ pub fn main() { box dogge2 as Box)); let (tx1, rx1) = channel(); let arc1 = arc.clone(); - let _t1 = thread::scoped(move|| { check_legs(arc1); tx1.send(()); }); + let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); let (tx2, rx2) = channel(); let arc2 = arc.clone(); - let _t2 = thread::scoped(move|| { check_names(arc2); tx2.send(()); }); + let t2 = thread::spawn(move|| { check_names(arc2); tx2.send(()); }); let (tx3, rx3) = channel(); let arc3 = arc.clone(); - let _t3 = thread::scoped(move|| { check_pedigree(arc3); tx3.send(()); }); + let t3 = thread::spawn(move|| { check_pedigree(arc3); tx3.send(()); }); rx1.recv(); rx2.recv(); rx3.recv(); + t1.join(); + t2.join(); + t3.join(); } fn check_legs(arc: Arc>>) { diff --git a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs index 60c1816b16..bb8ae8247f 100644 --- a/src/test/run-pass/trait-bounds-on-structs-and-enums.rs +++ b/src/test/run-pass/trait-bounds-on-structs-and-enums.rs @@ -12,10 +12,10 @@ #![feature(core)] -trait U : ::std::marker::MarkerTrait {} +trait U {} trait T { fn get(self) -> X; } -trait S2 : ::std::marker::MarkerTrait { +trait S2 { fn m(x: Box+'static>) {} } diff --git a/src/test/run-pass/trait-bounds-recursion.rs b/src/test/run-pass/trait-bounds-recursion.rs index 250390f70b..d984e9cdc9 100644 --- a/src/test/run-pass/trait-bounds-recursion.rs +++ b/src/test/run-pass/trait-bounds-recursion.rs @@ -10,21 +10,19 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - trait I { fn i(&self) -> Self; } -trait A : ::std::marker::MarkerTrait { +trait A { fn id(x:T) -> T { x.i() } } trait J { fn j(&self) -> T; } -trait B> : ::std::marker::MarkerTrait { +trait B> { fn id(x:T) -> T { x.j() } } -trait C : ::std::marker::MarkerTrait { +trait C { fn id>(x:T) -> T { x.j() } } diff --git a/src/test/run-pass/trait-bounds.rs b/src/test/run-pass/trait-bounds.rs index 642119df15..d501fef122 100644 --- a/src/test/run-pass/trait-bounds.rs +++ b/src/test/run-pass/trait-bounds.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait connection { fn read(&self) -> isize; diff --git a/src/test/run-pass/trait-default-method-bound-subst.rs b/src/test/run-pass/trait-default-method-bound-subst.rs index e936989537..b9936bcadd 100644 --- a/src/test/run-pass/trait-default-method-bound-subst.rs +++ b/src/test/run-pass/trait-default-method-bound-subst.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T, y: U) -> (T, U) { (x, y) } diff --git a/src/test/run-pass/trait-default-method-bound-subst2.rs b/src/test/run-pass/trait-default-method-bound-subst2.rs index 4fedbba81f..92b9449461 100644 --- a/src/test/run-pass/trait-default-method-bound-subst2.rs +++ b/src/test/run-pass/trait-default-method-bound-subst2.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T) -> T { x } diff --git a/src/test/run-pass/trait-default-method-bound-subst3.rs b/src/test/run-pass/trait-default-method-bound-subst3.rs index 4f749cbd3f..af7e883033 100644 --- a/src/test/run-pass/trait-default-method-bound-subst3.rs +++ b/src/test/run-pass/trait-default-method-bound-subst3.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: T, y: T) -> (T, T) { (x, y) } diff --git a/src/test/run-pass/trait-default-method-bound-subst4.rs b/src/test/run-pass/trait-default-method-bound-subst4.rs index 6774569cd2..581a54e57f 100644 --- a/src/test/run-pass/trait-default-method-bound-subst4.rs +++ b/src/test/run-pass/trait-default-method-bound-subst4.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self, x: usize) -> usize { x } diff --git a/src/test/run-pass/trait-default-method-bound.rs b/src/test/run-pass/trait-default-method-bound.rs index 4107540a47..e0ea9651f6 100644 --- a/src/test/run-pass/trait-default-method-bound.rs +++ b/src/test/run-pass/trait-default-method-bound.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn g(&self) -> isize { 10 } diff --git a/src/test/run-pass/trait-default-method-xc-2.rs b/src/test/run-pass/trait-default-method-xc-2.rs index d4ed727040..833063d2a2 100644 --- a/src/test/run-pass/trait-default-method-xc-2.rs +++ b/src/test/run-pass/trait-default-method-xc-2.rs @@ -12,7 +12,6 @@ // aux-build:trait_default_method_xc_aux_2.rs -// pretty-expanded FIXME #23616 extern crate trait_default_method_xc_aux as aux; extern crate trait_default_method_xc_aux_2 as aux2; diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs index 65e8c53a25..72e3fb256c 100644 --- a/src/test/run-pass/trait-default-method-xc.rs +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_default_method_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_default_method_xc_aux as aux; use aux::{A, TestEquality, Something}; diff --git a/src/test/run-pass/trait-generic.rs b/src/test/run-pass/trait-generic.rs index 6ef0dacee7..4998236629 100644 --- a/src/test/run-pass/trait-generic.rs +++ b/src/test/run-pass/trait-generic.rs @@ -10,7 +10,6 @@ -// pretty-expanded FIXME #23616 trait to_str { fn to_string_(&self) -> String; diff --git a/src/test/run-pass/trait-impl.rs b/src/test/run-pass/trait-impl.rs index 95fd7bda47..10025a76f7 100644 --- a/src/test/run-pass/trait-impl.rs +++ b/src/test/run-pass/trait-impl.rs @@ -11,7 +11,6 @@ // Test calling methods on an impl for a bare trait. // aux-build:traitimpl.rs -// pretty-expanded FIXME #23616 extern crate traitimpl; use traitimpl::Bar; diff --git a/src/test/run-pass/trait-inheritance-auto-xc-2.rs b/src/test/run-pass/trait-inheritance-auto-xc-2.rs index 128be2993e..270cf652ed 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc-2.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc-2.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_auto_xc_2_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_auto_xc_2_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-auto-xc.rs b/src/test/run-pass/trait-inheritance-auto-xc.rs index 827674c81a..eaca60c935 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_auto_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_auto_xc_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs index 1b72736cde..75c48d5171 100644 --- a/src/test/run-pass/trait-inheritance-auto.rs +++ b/src/test/run-pass/trait-inheritance-auto.rs @@ -10,7 +10,6 @@ // Testing that this impl turns A into a Quux, because // A is already a Foo Bar Baz -// pretty-expanded FIXME #23616 impl Quux for T { } diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs index c8df12392f..2fb2b9274c 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs index fcd6143579..87dc04f1c6 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs index 3996ae850e..dd61dc0f9f 100644 --- a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs +++ b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs @@ -11,7 +11,6 @@ // Testing that we can cast to a subtrait and call subtrait // methods. Not testing supertrait methods -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; diff --git a/src/test/run-pass/trait-inheritance-cast.rs b/src/test/run-pass/trait-inheritance-cast.rs index 7784ed2f26..0de2c58693 100644 --- a/src/test/run-pass/trait-inheritance-cast.rs +++ b/src/test/run-pass/trait-inheritance-cast.rs @@ -10,7 +10,6 @@ // Testing that supertrait methods can be called on subtrait object types -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index c665c35b41..e1610c1db0 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_cross_trait_call_xc_aux.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_cross_trait_call_xc_aux as aux; diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call.rs b/src/test/run-pass/trait-inheritance-cross-trait-call.rs index 418986f961..27b0f66603 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-diamond.rs b/src/test/run-pass/trait-inheritance-diamond.rs index 07b1a79110..43151bb0f9 100644 --- a/src/test/run-pass/trait-inheritance-diamond.rs +++ b/src/test/run-pass/trait-inheritance-diamond.rs @@ -10,7 +10,6 @@ // B and C both require A, so D does as well, twice, but that's just fine -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-multiple-inheritors.rs b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs index b892462695..8125ce2091 100644 --- a/src/test/run-pass/trait-inheritance-multiple-inheritors.rs +++ b/src/test/run-pass/trait-inheritance-multiple-inheritors.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-multiple-params.rs b/src/test/run-pass/trait-inheritance-multiple-params.rs index 37803edb75..c0f7a9d9c2 100644 --- a/src/test/run-pass/trait-inheritance-multiple-params.rs +++ b/src/test/run-pass/trait-inheritance-multiple-params.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait A { fn a(&self) -> isize; } trait B: A { fn b(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 4af049fc0c..e5390ac8a6 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -10,16 +10,11 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::cmp::{PartialEq, PartialOrd}; -use std::num::NumCast; - -pub trait NumExt: NumCast + PartialEq + PartialOrd {} +pub trait NumExt: PartialEq + PartialOrd {} pub trait FloatExt: NumExt {} -fn greater_than_one(n: &T) -> bool { *n > NumCast::from(1).unwrap() } -fn greater_than_one_float(n: &T) -> bool { *n > NumCast::from(1).unwrap() } +fn greater_than_one(n: &T) -> bool { loop {} } +fn greater_than_one_float(n: &T) -> bool { loop {} } pub fn main() {} diff --git a/src/test/run-pass/trait-inheritance-num0.rs b/src/test/run-pass/trait-inheritance-num0.rs index b7f9534935..83c2a9ad33 100644 --- a/src/test/run-pass/trait-inheritance-num0.rs +++ b/src/test/run-pass/trait-inheritance-num0.rs @@ -15,7 +15,10 @@ #![feature(core)] use std::cmp::PartialOrd; -use std::num::NumCast; + +pub trait NumCast { + fn from(i: i32) -> Option; +} pub trait Num { fn from_int(i: isize) -> Self; diff --git a/src/test/run-pass/trait-inheritance-num1.rs b/src/test/run-pass/trait-inheritance-num1.rs index 02ebf6bfa5..14a6a9a0c6 100644 --- a/src/test/run-pass/trait-inheritance-num1.rs +++ b/src/test/run-pass/trait-inheritance-num1.rs @@ -10,10 +10,9 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::cmp::PartialOrd; -use std::num::NumCast; +pub trait NumCast { + fn from(i: i32) -> Option; +} pub trait NumExt: NumCast + PartialOrd { } diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index 773fc387a2..5f8541a6da 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -10,12 +10,7 @@ // A more complex example of numeric extensions -#![feature(core)] - -use std::cmp::{PartialEq, PartialOrd}; -use std::num::NumCast; - -pub trait TypeExt : ::std::marker::MarkerTrait { } +pub trait TypeExt {} impl TypeExt for u8 {} impl TypeExt for u16 {} @@ -33,7 +28,7 @@ impl TypeExt for f32 {} impl TypeExt for f64 {} -pub trait NumExt: TypeExt + PartialEq + PartialOrd + NumCast {} +pub trait NumExt: TypeExt + PartialEq + PartialOrd {} impl NumExt for u8 {} impl NumExt for u16 {} diff --git a/src/test/run-pass/trait-inheritance-num3.rs b/src/test/run-pass/trait-inheritance-num3.rs index b5cf25bc5a..abf8d2baf8 100644 --- a/src/test/run-pass/trait-inheritance-num3.rs +++ b/src/test/run-pass/trait-inheritance-num3.rs @@ -8,14 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(core)] - -use std::cmp::{PartialEq, PartialOrd}; -use std::num::NumCast; +pub trait NumCast { + fn from(i: i32) -> Option; +} pub trait NumExt: PartialEq + PartialOrd + NumCast {} impl NumExt for f32 {} +impl NumCast for f32 { + fn from(i: i32) -> Option { Some(i as f32) } +} fn num_eq_one(n: T) { println!("{}", n == NumCast::from(1).unwrap()) diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs index b2c3900bc0..c6f8a5d4f1 100644 --- a/src/test/run-pass/trait-inheritance-num5.rs +++ b/src/test/run-pass/trait-inheritance-num5.rs @@ -10,16 +10,22 @@ // pretty-expanded FIXME #23616 -#![feature(core)] - -use std::cmp::PartialEq; -use std::num::NumCast; +pub trait NumCast { + fn from(i: i32) -> Option; +} pub trait NumExt: PartialEq + NumCast {} impl NumExt for f32 {} impl NumExt for isize {} +impl NumCast for f32 { + fn from(i: i32) -> Option { Some(i as f32) } +} +impl NumCast for isize { + fn from(i: i32) -> Option { Some(i as isize) } +} + fn num_eq_one() -> T { NumCast::from(1).unwrap() } diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index f44c6927c8..21d6c53a46 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -10,7 +10,6 @@ // aux-build:trait_inheritance_overloading_xc.rs -// pretty-expanded FIXME #23616 extern crate trait_inheritance_overloading_xc; use trait_inheritance_overloading_xc::{MyNum, MyInt}; diff --git a/src/test/run-pass/trait-inheritance-self-in-supertype.rs b/src/test/run-pass/trait-inheritance-self-in-supertype.rs index 87a36ba7b9..c7e206cb47 100644 --- a/src/test/run-pass/trait-inheritance-self-in-supertype.rs +++ b/src/test/run-pass/trait-inheritance-self-in-supertype.rs @@ -10,10 +10,6 @@ // Test for issue #4183: use of Self in supertraits. -// pretty-expanded FIXME #23616 - -use std::num::Float as StdFloat; - pub static FUZZY_EPSILON: f64 = 0.1; pub trait FuzzyEq { diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs index ff89b1ee5d..917e520339 100644 --- a/src/test/run-pass/trait-inheritance-simple.rs +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar : Foo { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance-static.rs b/src/test/run-pass/trait-inheritance-static.rs index 9ed5fd0aaa..8e56582951 100644 --- a/src/test/run-pass/trait-inheritance-static.rs +++ b/src/test/run-pass/trait-inheritance-static.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub trait MyNum { fn from_int(isize) -> Self; diff --git a/src/test/run-pass/trait-inheritance-static2.rs b/src/test/run-pass/trait-inheritance-static2.rs index 9fe9d7fce7..67bea3864a 100644 --- a/src/test/run-pass/trait-inheritance-static2.rs +++ b/src/test/run-pass/trait-inheritance-static2.rs @@ -8,13 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +pub trait MyEq {} -#![feature(core)] - -pub trait MyEq : ::std::marker::MarkerTrait { } - -pub trait MyNum : ::std::marker::MarkerTrait { +pub trait MyNum { fn from_int(isize) -> Self; } diff --git a/src/test/run-pass/trait-inheritance-subst.rs b/src/test/run-pass/trait-inheritance-subst.rs index d35a937a57..6074c8a71b 100644 --- a/src/test/run-pass/trait-inheritance-subst.rs +++ b/src/test/run-pass/trait-inheritance-subst.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub trait Add { fn add(&self, rhs: &RHS) -> Result; diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs index e0be575950..6a36399543 100644 --- a/src/test/run-pass/trait-inheritance-subst2.rs +++ b/src/test/run-pass/trait-inheritance-subst2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Panda { fn chomp(&self, bamboo: &T) -> T; diff --git a/src/test/run-pass/trait-inheritance-visibility.rs b/src/test/run-pass/trait-inheritance-visibility.rs index 8c8b9232de..f00a4f2ecb 100644 --- a/src/test/run-pass/trait-inheritance-visibility.rs +++ b/src/test/run-pass/trait-inheritance-visibility.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 mod traits { pub trait Foo { fn f(&self) -> isize; } diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs index 9e721836d6..2161c0f894 100644 --- a/src/test/run-pass/trait-inheritance2.rs +++ b/src/test/run-pass/trait-inheritance2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn f(&self) -> isize; } trait Bar { fn g(&self) -> isize; } diff --git a/src/test/run-pass/trait-object-generics.rs b/src/test/run-pass/trait-object-generics.rs index 63246b870c..15a8a2e83e 100644 --- a/src/test/run-pass/trait-object-generics.rs +++ b/src/test/run-pass/trait-object-generics.rs @@ -10,7 +10,6 @@ // test for #8664 -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/trait-object-with-lifetime-bound.rs b/src/test/run-pass/trait-object-with-lifetime-bound.rs index 30a05ee1c5..21b84221d0 100644 --- a/src/test/run-pass/trait-object-with-lifetime-bound.rs +++ b/src/test/run-pass/trait-object-with-lifetime-bound.rs @@ -11,7 +11,6 @@ // Uncovered during work on new scoping rules for safe destructors // as an important use case to support properly. -// pretty-expanded FIXME #23616 pub struct E<'a> { pub f: &'a u8, diff --git a/src/test/run-pass/trait-safety-ok-cc.rs b/src/test/run-pass/trait-safety-ok-cc.rs index ada7939956..abbc556f34 100644 --- a/src/test/run-pass/trait-safety-ok-cc.rs +++ b/src/test/run-pass/trait-safety-ok-cc.rs @@ -12,7 +12,6 @@ // Simple smoke test that unsafe traits can be compiled across crates. -// pretty-expanded FIXME #23616 extern crate trait_safety_lib as lib; diff --git a/src/test/run-pass/trait-safety-ok.rs b/src/test/run-pass/trait-safety-ok.rs index 3cd23aeaf2..0ccc6cd152 100644 --- a/src/test/run-pass/trait-safety-ok.rs +++ b/src/test/run-pass/trait-safety-ok.rs @@ -10,7 +10,6 @@ // Simple smoke test that unsafe traits can be compiled etc. -// pretty-expanded FIXME #23616 unsafe trait Foo { fn foo(&self) -> isize; diff --git a/src/test/run-pass/traits-assoc-type-in-supertrait.rs b/src/test/run-pass/traits-assoc-type-in-supertrait.rs index 751cd50441..5cecacafc7 100644 --- a/src/test/run-pass/traits-assoc-type-in-supertrait.rs +++ b/src/test/run-pass/traits-assoc-type-in-supertrait.rs @@ -11,7 +11,6 @@ // Test case where an associated type is referenced from within the // supertrait definition. Issue #20220. -// pretty-expanded FIXME #23616 use std::vec::IntoIter; diff --git a/src/test/run-pass/traits-conditional-dispatch.rs b/src/test/run-pass/traits-conditional-dispatch.rs index 0190b7b7b9..8d2faaf418 100644 --- a/src/test/run-pass/traits-conditional-dispatch.rs +++ b/src/test/run-pass/traits-conditional-dispatch.rs @@ -12,18 +12,15 @@ // blanket impl for T:Copy coexists with an impl for Box, because // Box does not impl Copy. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] -use std::marker::MarkerTrait; - trait Get { fn get(&self) -> Self; } -trait MyCopy : MarkerTrait { fn copy(&self) -> Self; } +trait MyCopy { fn copy(&self) -> Self; } impl MyCopy for u16 { fn copy(&self) -> Self { *self } } impl MyCopy for u32 { fn copy(&self) -> Self { *self } } impl MyCopy for i32 { fn copy(&self) -> Self { *self } } diff --git a/src/test/run-pass/traits-conditional-model-fn.rs b/src/test/run-pass/traits-conditional-model-fn.rs index 65a4884462..d19f7143ed 100644 --- a/src/test/run-pass/traits-conditional-model-fn.rs +++ b/src/test/run-pass/traits-conditional-model-fn.rs @@ -14,7 +14,6 @@ // aux-build:go_trait.rs -// pretty-expanded FIXME #23616 extern crate go_trait; diff --git a/src/test/run-pass/traits-default-method-macro.rs b/src/test/run-pass/traits-default-method-macro.rs index 1ec58eac58..193038d9e5 100644 --- a/src/test/run-pass/traits-default-method-macro.rs +++ b/src/test/run-pass/traits-default-method-macro.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 trait Foo { fn bar(&self) -> String { diff --git a/src/test/run-pass/traits-impl-object-overlap-issue-23853.rs b/src/test/run-pass/traits-impl-object-overlap-issue-23853.rs new file mode 100644 index 0000000000..b9b2b50613 --- /dev/null +++ b/src/test/run-pass/traits-impl-object-overlap-issue-23853.rs @@ -0,0 +1,27 @@ +// 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. + +// Test that we are able to compile the case where both a blanket impl +// and the object type itself supply the required trait obligation. +// In this case, the blanket impl for `Foo` applies to any type, +// including `Bar`, but the object type `Bar` also implicitly supplies +// this context. + +trait Foo { fn dummy(&self) { } } + +trait Bar: Foo { } + +impl Foo for T { } + +fn want_foo() { } + +fn main() { + want_foo::(); +} diff --git a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs index 1f1d1a46cf..6634c1ad0a 100644 --- a/src/test/run-pass/traits-multidispatch-infer-convert-target.rs +++ b/src/test/run-pass/traits-multidispatch-infer-convert-target.rs @@ -10,7 +10,6 @@ // Test that we can infer the Target based on the Self or vice versa. -// pretty-expanded FIXME #23616 use std::mem; diff --git a/src/test/run-pass/traits-repeated-supertrait.rs b/src/test/run-pass/traits-repeated-supertrait.rs index 509a6e36af..b059945ef7 100644 --- a/src/test/run-pass/traits-repeated-supertrait.rs +++ b/src/test/run-pass/traits-repeated-supertrait.rs @@ -13,7 +13,6 @@ // various methods in various ways successfully. // See also `compile-fail/trait-repeated-supertrait-ambig.rs`. -// pretty-expanded FIXME #23616 trait CompareTo { fn same_as(&self, t: T) -> bool; diff --git a/src/test/run-pass/trans-tag-static-padding.rs b/src/test/run-pass/trans-tag-static-padding.rs index 3e2297f008..ba01d51dc6 100644 --- a/src/test/run-pass/trans-tag-static-padding.rs +++ b/src/test/run-pass/trans-tag-static-padding.rs @@ -21,7 +21,6 @@ // Last 7 bytes of Request struct are not occupied by any fields. -// pretty-expanded FIXME #23616 enum TestOption { TestNone, diff --git a/src/test/run-pass/tup.rs b/src/test/run-pass/tup.rs index 50687756e2..86ca37deb0 100644 --- a/src/test/run-pass/tup.rs +++ b/src/test/run-pass/tup.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 type point = (isize, isize); diff --git a/src/test/run-pass/tuple-index-fat-types.rs b/src/test/run-pass/tuple-index-fat-types.rs index 395531d157..e4ea073bfc 100644 --- a/src/test/run-pass/tuple-index-fat-types.rs +++ b/src/test/run-pass/tuple-index-fat-types.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Foo<'a>(&'a [isize]); diff --git a/src/test/run-pass/tuple-index.rs b/src/test/run-pass/tuple-index.rs index a70b49296f..26d918f236 100644 --- a/src/test/run-pass/tuple-index.rs +++ b/src/test/run-pass/tuple-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct Point(isize, isize); diff --git a/src/test/run-pass/tydesc-name.rs b/src/test/run-pass/tydesc-name.rs index 4ba7e786ec..1534c301c9 100644 --- a/src/test/run-pass/tydesc-name.rs +++ b/src/test/run-pass/tydesc-name.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/type-id-higher-rank.rs b/src/test/run-pass/type-id-higher-rank.rs index ec5aa2863a..3030833c77 100644 --- a/src/test/run-pass/type-id-higher-rank.rs +++ b/src/test/run-pass/type-id-higher-rank.rs @@ -11,7 +11,6 @@ // Test that type IDs correctly account for higher-rank lifetimes // Also acts as a regression test for an ICE (issue #19791) -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/type-namespace.rs b/src/test/run-pass/type-namespace.rs index c03ddd0c64..36f8b2ca5b 100644 --- a/src/test/run-pass/type-namespace.rs +++ b/src/test/run-pass/type-namespace.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 struct A { a: isize } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 8c1251feea..fc6499ce5d 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/typeck-macro-interaction-issue-8852.rs b/src/test/run-pass/typeck-macro-interaction-issue-8852.rs index 2da8b0a508..696e151a80 100644 --- a/src/test/run-pass/typeck-macro-interaction-issue-8852.rs +++ b/src/test/run-pass/typeck-macro-interaction-issue-8852.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 enum T { A(isize), diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index 53e78db68b..113d52ffb3 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -11,7 +11,6 @@ // This test checks that the `_` type placeholder works // correctly for enabling type inference. -// pretty-expanded FIXME #23616 struct TestStruct { x: *const isize diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index 7a143ce588..9741ed0fdd 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -11,7 +11,6 @@ // aux-build:typeid-intrinsic.rs // aux-build:typeid-intrinsic2.rs -// pretty-expanded FIXME #23616 #![feature(hash, core)] diff --git a/src/test/run-pass/typestate-multi-decl.rs b/src/test/run-pass/typestate-multi-decl.rs index c7762a8464..0749b52a1c 100644 --- a/src/test/run-pass/typestate-multi-decl.rs +++ b/src/test/run-pass/typestate-multi-decl.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let (x, y) = (10, 20); diff --git a/src/test/run-pass/u32-decr.rs b/src/test/run-pass/u32-decr.rs index 4955ac8a4b..b56b6f32c0 100644 --- a/src/test/run-pass/u32-decr.rs +++ b/src/test/run-pass/u32-decr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut word: u32 = 200000; diff --git a/src/test/run-pass/u8-incr-decr.rs b/src/test/run-pass/u8-incr-decr.rs index 7c67d304ed..d35ef015e6 100644 --- a/src/test/run-pass/u8-incr-decr.rs +++ b/src/test/run-pass/u8-incr-decr.rs @@ -14,7 +14,6 @@ // These constants were chosen because they aren't used anywhere // in the rest of the generated code so they're easily grep-able. -// pretty-expanded FIXME #23616 pub fn main() { let mut x: u8 = 19; // 0x13 diff --git a/src/test/run-pass/u8-incr.rs b/src/test/run-pass/u8-incr.rs index e15576c3fa..9554f9c2df 100644 --- a/src/test/run-pass/u8-incr.rs +++ b/src/test/run-pass/u8-incr.rs @@ -11,7 +11,6 @@ -// pretty-expanded FIXME #23616 pub fn main() { let mut x: u8 = 12; diff --git a/src/test/run-pass/ufcs-polymorphic-paths.rs b/src/test/run-pass/ufcs-polymorphic-paths.rs index a6ea0f76dc..eec852ae18 100644 --- a/src/test/run-pass/ufcs-polymorphic-paths.rs +++ b/src/test/run-pass/ufcs-polymorphic-paths.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections, rand, into_cow)] @@ -18,11 +17,19 @@ use std::default::Default; use std::iter::FromIterator; use std::ops::Add; use std::option::IntoIter as OptionIter; -use std::rand::Rand; -use std::rand::XorShiftRng as DummyRng; -// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods. +// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent +// methods. use std::vec::Vec; +pub struct XorShiftRng; +use XorShiftRng as DummyRng; +impl Rng for XorShiftRng {} +pub trait Rng {} +pub trait Rand: Default + Sized { + fn rand(rng: &mut R) -> Self { Default::default() } +} +impl Rand for i32 { } + #[derive(PartialEq, Eq)] struct Newt(T); @@ -30,7 +37,7 @@ fn id(x: T) -> T { x } fn eq(a: T, b: T) -> bool { a == b } fn u8_as_i8(x: u8) -> i8 { x as i8 } fn odd(x: usize) -> bool { x % 2 == 1 } -fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } +fn dummy_rng() -> DummyRng { XorShiftRng } trait Size: Sized { fn size() -> usize { std::mem::size_of::() } diff --git a/src/test/run-pass/ufcs-trait-object.rs b/src/test/run-pass/ufcs-trait-object.rs index b242018458..457beeb3f3 100644 --- a/src/test/run-pass/ufcs-trait-object.rs +++ b/src/test/run-pass/ufcs-trait-object.rs @@ -11,7 +11,6 @@ // Test that when you use ufcs form to invoke a trait method (on a // trait object) everything works fine. -// pretty-expanded FIXME #23616 trait Foo { fn test(&self) -> i32; diff --git a/src/test/run-pass/unboxed-closures-all-traits.rs b/src/test/run-pass/unboxed-closures-all-traits.rs index 9ca8e5403a..c28d4f463e 100644 --- a/src/test/run-pass/unboxed-closures-all-traits.rs +++ b/src/test/run-pass/unboxed-closures-all-traits.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs index 37dccca1e2..54c92900c8 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -10,7 +10,6 @@ // Test that you can supply `&F` where `F: FnMut()`. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs index 0f93966077..eb47447309 100644 --- a/src/test/run-pass/unboxed-closures-blanket-fn.rs +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -10,7 +10,6 @@ // Test that you can supply `&F` where `F: Fn()`. -// pretty-expanded FIXME #23616 #![feature(lang_items, unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-by-ref.rs b/src/test/run-pass/unboxed-closures-by-ref.rs index 7855cf6ba0..e3ddfdbac0 100644 --- a/src/test/run-pass/unboxed-closures-by-ref.rs +++ b/src/test/run-pass/unboxed-closures-by-ref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs index 6e92850ac2..64236ce563 100644 --- a/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-fn-autoderef.rs @@ -10,7 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs index 402b4b0b85..67ab84f027 100644 --- a/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs +++ b/src/test/run-pass/unboxed-closures-call-sugar-autoderef.rs @@ -10,7 +10,6 @@ // Test that the call operator autoderefs when calling a bounded type parameter. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-counter-not-moved.rs b/src/test/run-pass/unboxed-closures-counter-not-moved.rs index 792d172277..cb5f190bcd 100644 --- a/src/test/run-pass/unboxed-closures-counter-not-moved.rs +++ b/src/test/run-pass/unboxed-closures-counter-not-moved.rs @@ -10,7 +10,6 @@ // Test that we mutate a counter on the stack only when we expect to. -// pretty-expanded FIXME #23616 fn call(f: F) where F : FnOnce() { f(); diff --git a/src/test/run-pass/unboxed-closures-cross-crate.rs b/src/test/run-pass/unboxed-closures-cross-crate.rs index 0c255c6bd6..37dc760ced 100644 --- a/src/test/run-pass/unboxed-closures-cross-crate.rs +++ b/src/test/run-pass/unboxed-closures-cross-crate.rs @@ -12,7 +12,6 @@ // Acts as a regression test for #16790, #18378 and #18543 // aux-build:unboxed-closures-cross-crate.rs -// pretty-expanded FIXME #23616 extern crate unboxed_closures_cross_crate as ubcc; diff --git a/src/test/run-pass/unboxed-closures-drop.rs b/src/test/run-pass/unboxed-closures-drop.rs index f0c6c0ff45..78f4905aef 100644 --- a/src/test/run-pass/unboxed-closures-drop.rs +++ b/src/test/run-pass/unboxed-closures-drop.rs @@ -11,7 +11,6 @@ // A battery of tests to ensure destructors of unboxed closure environments // run at the right times. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs index 4af4b320d0..e71757abd0 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs @@ -10,7 +10,6 @@ // Checks that higher-ranked extern fn pointers implement the full range of Fn traits. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index d711ebbe4b..57acbae4ce 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -10,7 +10,6 @@ // Checks that extern fn pointers implement the full range of Fn traits. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs index 9b71abf365..5d6d372ea5 100644 --- a/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fn-as-fnmut-and-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // any Fn trait to be used where Fn is implemented. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs index 6261058b86..c19b5b273c 100644 --- a/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-fnmut-as-fnonce.rs @@ -11,7 +11,6 @@ // Checks that the Fn trait hierarchy rules permit // FnMut or FnOnce to be used where FnMut is implemented. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-bound.rs b/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-bound.rs index d408612f9b..c4944548e1 100644 --- a/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-bound.rs +++ b/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-bound.rs @@ -13,14 +13,18 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures, core)] +pub trait ToPrimitive { + fn to_int(&self) {} +} -use std::num::ToPrimitive; +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} fn doit(val: T, f: &F) where F : Fn(T) { - f.call((val,)) + f(val) } pub fn main() { diff --git a/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-object-type.rs b/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-object-type.rs index c1e1ff3cd8..9cad7d61e3 100644 --- a/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-object-type.rs +++ b/src/test/run-pass/unboxed-closures-infer-argument-types-from-expected-object-type.rs @@ -13,11 +13,15 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures, core)] +pub trait ToPrimitive { + fn to_int(&self) {} +} -use std::num::ToPrimitive; +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} -fn doit(val: T, f: &Fn(T)) { f.call((val,)) } +fn doit(val: T, f: &Fn(T)) { f(val) } pub fn main() { doit(0, &|x /*: isize*/ | { x.to_int(); }); diff --git a/src/test/run-pass/unboxed-closures-infer-argument-types-with-bound-regions-from-expected-bound.rs b/src/test/run-pass/unboxed-closures-infer-argument-types-with-bound-regions-from-expected-bound.rs index 99e2149de9..bdd1932182 100644 --- a/src/test/run-pass/unboxed-closures-infer-argument-types-with-bound-regions-from-expected-bound.rs +++ b/src/test/run-pass/unboxed-closures-infer-argument-types-with-bound-regions-from-expected-bound.rs @@ -13,14 +13,18 @@ // pretty-expanded FIXME #23616 -#![feature(unboxed_closures, core)] +pub trait ToPrimitive { + fn to_int(&self) {} +} -use std::num::ToPrimitive; +impl ToPrimitive for isize {} +impl ToPrimitive for i32 {} +impl ToPrimitive for usize {} fn doit(val: T, f: &F) where F : Fn(&T) { - f.call((&val,)) + f(&val) } pub fn main() { diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs index 798959f69d..2da899ed95 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-calling-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs index 5b1e35a3e5..32fc3433e8 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut-move.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this `move` // closure that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnmut.rs b/src/test/run-pass/unboxed-closures-infer-fnmut.rs index cd7f26bba2..a8469f4019 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnmut.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnmut.rs @@ -11,7 +11,6 @@ // Test that we are able to infer a suitable kind for this closure // that is just called (`FnMut`). -// pretty-expanded FIXME #23616 fn main() { let mut counter = 0; diff --git a/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs b/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs index dc106614b5..dcda724c7b 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnonce-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/unboxed-closures-infer-fnonce.rs b/src/test/run-pass/unboxed-closures-infer-fnonce.rs index 036b32a44d..275ba0520c 100644 --- a/src/test/run-pass/unboxed-closures-infer-fnonce.rs +++ b/src/test/run-pass/unboxed-closures-infer-fnonce.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/unboxed-closures-infer-kind.rs b/src/test/run-pass/unboxed-closures-infer-kind.rs index edc01d91f5..fa668475f5 100644 --- a/src/test/run-pass/unboxed-closures-infer-kind.rs +++ b/src/test/run-pass/unboxed-closures-infer-kind.rs @@ -11,7 +11,6 @@ // Test that we can infer the "kind" of an unboxed closure based on // the expected type. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs index e02784f917..e499ab5cca 100644 --- a/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs +++ b/src/test/run-pass/unboxed-closures-infer-recursive-fn.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(core,unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-infer-upvar.rs b/src/test/run-pass/unboxed-closures-infer-upvar.rs index e29632b007..f2423145b1 100644 --- a/src/test/run-pass/unboxed-closures-infer-upvar.rs +++ b/src/test/run-pass/unboxed-closures-infer-upvar.rs @@ -11,7 +11,6 @@ // Test that the type variable in the type(`Vec<_>`) of a closed over // variable does not interfere with type inference. -// pretty-expanded FIXME #23616 fn f(mut f: F) { f(); diff --git a/src/test/run-pass/unboxed-closures-manual-impl.rs b/src/test/run-pass/unboxed-closures-manual-impl.rs index 38f15d6e44..6a76fdb5ad 100644 --- a/src/test/run-pass/unboxed-closures-manual-impl.rs +++ b/src/test/run-pass/unboxed-closures-manual-impl.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures, core)] diff --git a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs index b69153b73a..e2b286738e 100644 --- a/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs +++ b/src/test/run-pass/unboxed-closures-move-some-upvars-in-by-ref-closure.rs @@ -11,7 +11,6 @@ // Test that in a by-ref once closure we move some variables even as // we capture others by mutable reference. -// pretty-expanded FIXME #23616 fn call(f: F) where F : FnOnce() { f(); diff --git a/src/test/run-pass/unboxed-closures-simple.rs b/src/test/run-pass/unboxed-closures-simple.rs index 1443d305bc..ec34198166 100644 --- a/src/test/run-pass/unboxed-closures-simple.rs +++ b/src/test/run-pass/unboxed-closures-simple.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-single-word-env.rs b/src/test/run-pass/unboxed-closures-single-word-env.rs index 65a26d14e1..166054e88b 100644 --- a/src/test/run-pass/unboxed-closures-single-word-env.rs +++ b/src/test/run-pass/unboxed-closures-single-word-env.rs @@ -11,7 +11,6 @@ // Ensures that single-word environments work right in unboxed closures. // These take a different path in codegen. -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-sugar-object.rs b/src/test/run-pass/unboxed-closures-sugar-object.rs index 77beeb13fb..49b9b7f061 100644 --- a/src/test/run-pass/unboxed-closures-sugar-object.rs +++ b/src/test/run-pass/unboxed-closures-sugar-object.rs @@ -10,7 +10,6 @@ // Test unboxed closure sugar used in object types. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unboxed-closures-unique-type-id.rs b/src/test/run-pass/unboxed-closures-unique-type-id.rs index 403b2ca9aa..de7eeb57de 100644 --- a/src/test/run-pass/unboxed-closures-unique-type-id.rs +++ b/src/test/run-pass/unboxed-closures-unique-type-id.rs @@ -19,7 +19,6 @@ // // compile-flags: -g -// pretty-expanded FIXME #23616 #![feature(unboxed_closures)] diff --git a/src/test/run-pass/unfold-cross-crate.rs b/src/test/run-pass/unfold-cross-crate.rs index fceccb499c..5c699bf304 100644 --- a/src/test/run-pass/unfold-cross-crate.rs +++ b/src/test/run-pass/unfold-cross-crate.rs @@ -10,7 +10,6 @@ // no-pretty-expanded FIXME #15189 -// pretty-expanded FIXME #23616 #![feature(core)] diff --git a/src/test/run-pass/uniq-self-in-mut-slot.rs b/src/test/run-pass/uniq-self-in-mut-slot.rs index a6408128c3..baca157a48 100644 --- a/src/test/run-pass/uniq-self-in-mut-slot.rs +++ b/src/test/run-pass/uniq-self-in-mut-slot.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign-copy.rs b/src/test/run-pass/unique-assign-copy.rs index 32a0713ca9..3323b3c046 100644 --- a/src/test/run-pass/unique-assign-copy.rs +++ b/src/test/run-pass/unique-assign-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign-drop.rs b/src/test/run-pass/unique-assign-drop.rs index 715fa548a7..37aa1f0a64 100644 --- a/src/test/run-pass/unique-assign-drop.rs +++ b/src/test/run-pass/unique-assign-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(dead_assignment)] #![allow(unknown_features)] diff --git a/src/test/run-pass/unique-assign-generic.rs b/src/test/run-pass/unique-assign-generic.rs index ca145479a3..249b734a69 100644 --- a/src/test/run-pass/unique-assign-generic.rs +++ b/src/test/run-pass/unique-assign-generic.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-assign.rs b/src/test/run-pass/unique-assign.rs index e4e7b69671..8e97fdd4a6 100644 --- a/src/test/run-pass/unique-assign.rs +++ b/src/test/run-pass/unique-assign.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-autoderef-field.rs b/src/test/run-pass/unique-autoderef-field.rs index 8ee1b28ea2..a711dbb685 100644 --- a/src/test/run-pass/unique-autoderef-field.rs +++ b/src/test/run-pass/unique-autoderef-field.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-autoderef-index.rs b/src/test/run-pass/unique-autoderef-index.rs index 9dc98cf2e3..c68ff1f061 100644 --- a/src/test/run-pass/unique-autoderef-index.rs +++ b/src/test/run-pass/unique-autoderef-index.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-cmp.rs b/src/test/run-pass/unique-cmp.rs index be7e46c869..3b0ad63aef 100644 --- a/src/test/run-pass/unique-cmp.rs +++ b/src/test/run-pass/unique-cmp.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-init-copy.rs b/src/test/run-pass/unique-decl-init-copy.rs index 0840f1308c..9d749803ff 100644 --- a/src/test/run-pass/unique-decl-init-copy.rs +++ b/src/test/run-pass/unique-decl-init-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-init.rs b/src/test/run-pass/unique-decl-init.rs index 1d5a44f45a..a00de08998 100644 --- a/src/test/run-pass/unique-decl-init.rs +++ b/src/test/run-pass/unique-decl-init.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl-move.rs b/src/test/run-pass/unique-decl-move.rs index 203a30e76b..f4ff44ffff 100644 --- a/src/test/run-pass/unique-decl-move.rs +++ b/src/test/run-pass/unique-decl-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-decl.rs b/src/test/run-pass/unique-decl.rs index 7404e8887e..bbf9b2f47a 100644 --- a/src/test/run-pass/unique-decl.rs +++ b/src/test/run-pass/unique-decl.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let _: Box; diff --git a/src/test/run-pass/unique-deref.rs b/src/test/run-pass/unique-deref.rs index 44681742a7..70b2617797 100644 --- a/src/test/run-pass/unique-deref.rs +++ b/src/test/run-pass/unique-deref.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-destructure.rs b/src/test/run-pass/unique-destructure.rs index 87bc6f6639..b368cbee2f 100644 --- a/src/test/run-pass/unique-destructure.rs +++ b/src/test/run-pass/unique-destructure.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-fn-arg-move.rs b/src/test/run-pass/unique-fn-arg-move.rs index e608ab9b63..d101cbd312 100644 --- a/src/test/run-pass/unique-fn-arg-move.rs +++ b/src/test/run-pass/unique-fn-arg-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-arg-mut.rs b/src/test/run-pass/unique-fn-arg-mut.rs index f0d2abfe27..ebe89b275d 100644 --- a/src/test/run-pass/unique-fn-arg-mut.rs +++ b/src/test/run-pass/unique-fn-arg-mut.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-arg.rs b/src/test/run-pass/unique-fn-arg.rs index 3d7ef31d02..97006d2a01 100644 --- a/src/test/run-pass/unique-fn-arg.rs +++ b/src/test/run-pass/unique-fn-arg.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-fn-ret.rs b/src/test/run-pass/unique-fn-ret.rs index bb1948bf3c..d3be0cf01f 100644 --- a/src/test/run-pass/unique-fn-ret.rs +++ b/src/test/run-pass/unique-fn-ret.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-in-vec-copy.rs b/src/test/run-pass/unique-in-vec-copy.rs index 129c0784cc..ab0e3ee809 100644 --- a/src/test/run-pass/unique-in-vec-copy.rs +++ b/src/test/run-pass/unique-in-vec-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-in-vec.rs b/src/test/run-pass/unique-in-vec.rs index dc94fa6ca4..4194582158 100644 --- a/src/test/run-pass/unique-in-vec.rs +++ b/src/test/run-pass/unique-in-vec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-kinds.rs b/src/test/run-pass/unique-kinds.rs index 96d54193ac..b808ac2b00 100644 --- a/src/test/run-pass/unique-kinds.rs +++ b/src/test/run-pass/unique-kinds.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-move-drop.rs b/src/test/run-pass/unique-move-drop.rs index e81095d548..530ba47891 100644 --- a/src/test/run-pass/unique-move-drop.rs +++ b/src/test/run-pass/unique-move-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unused_variable)] #![allow(unknown_features)] diff --git a/src/test/run-pass/unique-move-temp.rs b/src/test/run-pass/unique-move-temp.rs index 634a1569ac..4b93762520 100644 --- a/src/test/run-pass/unique-move-temp.rs +++ b/src/test/run-pass/unique-move-temp.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-move.rs b/src/test/run-pass/unique-move.rs index 29bf113926..bed1d6e171 100644 --- a/src/test/run-pass/unique-move.rs +++ b/src/test/run-pass/unique-move.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-mutable.rs b/src/test/run-pass/unique-mutable.rs index 106481e318..8beec6a419 100644 --- a/src/test/run-pass/unique-mutable.rs +++ b/src/test/run-pass/unique-mutable.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-pat-2.rs b/src/test/run-pass/unique-pat-2.rs index d16355af99..c314b70e53 100644 --- a/src/test/run-pass/unique-pat-2.rs +++ b/src/test/run-pass/unique-pat-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-pat.rs b/src/test/run-pass/unique-pat.rs index ae76179b5e..1312ea924b 100644 --- a/src/test/run-pass/unique-pat.rs +++ b/src/test/run-pass/unique-pat.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_patterns)] diff --git a/src/test/run-pass/unique-rec.rs b/src/test/run-pass/unique-rec.rs index 7a09e241ca..72975c27ee 100644 --- a/src/test/run-pass/unique-rec.rs +++ b/src/test/run-pass/unique-rec.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-send-2.rs b/src/test/run-pass/unique-send-2.rs index 99a3b64105..c32483f629 100644 --- a/src/test/run-pass/unique-send-2.rs +++ b/src/test/run-pass/unique-send-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] @@ -24,10 +23,10 @@ pub fn main() { let (tx, rx) = channel(); let n = 100; let mut expected = 0; - let _t = (0..n).map(|i| { + let ts = (0..n).map(|i| { expected += i; let tx = tx.clone(); - thread::scoped(move|| { + thread::spawn(move|| { child(&tx, i) }) }).collect::>(); @@ -39,4 +38,6 @@ pub fn main() { } assert_eq!(expected, actual); + + for t in ts { t.join(); } } diff --git a/src/test/run-pass/unique-send.rs b/src/test/run-pass/unique-send.rs index c9649ef60d..bc0f790b2b 100644 --- a/src/test/run-pass/unique-send.rs +++ b/src/test/run-pass/unique-send.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unique-swap.rs b/src/test/run-pass/unique-swap.rs index 454011a9ec..cfa076f1a0 100644 --- a/src/test/run-pass/unique-swap.rs +++ b/src/test/run-pass/unique-swap.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/unit-like-struct-drop-run.rs b/src/test/run-pass/unit-like-struct-drop-run.rs index c2db63ed25..e31d4c811f 100644 --- a/src/test/run-pass/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/unit-like-struct-drop-run.rs @@ -10,7 +10,6 @@ // Make sure the destructor is run for unit-like structs. -// pretty-expanded FIXME #23616 #![feature(alloc)] diff --git a/src/test/run-pass/unreachable-code-1.rs b/src/test/run-pass/unreachable-code-1.rs index 612beabb03..c1c069236c 100644 --- a/src/test/run-pass/unreachable-code-1.rs +++ b/src/test/run-pass/unreachable-code-1.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unreachable_code)] #![allow(unused_variable)] diff --git a/src/test/run-pass/unreachable-code.rs b/src/test/run-pass/unreachable-code.rs index 4f58df6625..e19fda5f87 100644 --- a/src/test/run-pass/unreachable-code.rs +++ b/src/test/run-pass/unreachable-code.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(path_statement)] #![allow(unreachable_code)] diff --git a/src/test/run-pass/unsafe-coercion.rs b/src/test/run-pass/unsafe-coercion.rs index d0c633e827..8661ebb414 100644 --- a/src/test/run-pass/unsafe-coercion.rs +++ b/src/test/run-pass/unsafe-coercion.rs @@ -10,7 +10,6 @@ // Check that safe fns are not a subtype of unsafe fns. -// pretty-expanded FIXME #23616 fn foo(x: i32) -> i32 { x * 22 diff --git a/src/test/run-pass/unsafe-pointer-assignability.rs b/src/test/run-pass/unsafe-pointer-assignability.rs index 75c7cabfcb..c8ee0f83b9 100644 --- a/src/test/run-pass/unsafe-pointer-assignability.rs +++ b/src/test/run-pass/unsafe-pointer-assignability.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn f(x: *const isize) { unsafe { diff --git a/src/test/run-pass/unsized.rs b/src/test/run-pass/unsized.rs index 8ff8169ef4..449d6b37e9 100644 --- a/src/test/run-pass/unsized.rs +++ b/src/test/run-pass/unsized.rs @@ -12,17 +12,17 @@ // pretty-expanded FIXME #23616 -use std::marker::{PhantomData, PhantomFn}; +use std::marker::PhantomData; -trait T1 : PhantomFn { } -pub trait T2 : PhantomFn { } -trait T3 : T2 + PhantomFn { } -trait T4 : PhantomFn<(Self,X)> {} -trait T5 : PhantomFn<(Self,X,Y)> {} -trait T6 : PhantomFn<(Self,X,Y)> {} -trait T7 : PhantomFn<(Self,X,Y)> {} -trait T8 : PhantomFn<(Self,X)> {} -trait T9 : PhantomFn<(Self,X)> {} +trait T1 { } +pub trait T2 { } +trait T3 : T2 { } +trait T4 { } +trait T5 { } +trait T6 { } +trait T7 { } +trait T8 { } +trait T9 { } struct S1(PhantomData); enum E { E1(PhantomData) } impl T1 for S1 {} diff --git a/src/test/run-pass/unsized3.rs b/src/test/run-pass/unsized3.rs index 8db294bdcc..2977f579fc 100644 --- a/src/test/run-pass/unsized3.rs +++ b/src/test/run-pass/unsized3.rs @@ -10,7 +10,6 @@ // Test structs with always-unsized fields. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, core)] diff --git a/src/test/run-pass/unwind-unique.rs b/src/test/run-pass/unwind-unique.rs index 1d6ce626c2..07bfc8062f 100644 --- a/src/test/run-pass/unwind-unique.rs +++ b/src/test/run-pass/unwind-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/utf8_idents.rs b/src/test/run-pass/utf8_idents.rs index b11b7e83eb..9f88d2b5dd 100644 --- a/src/test/run-pass/utf8_idents.rs +++ b/src/test/run-pass/utf8_idents.rs @@ -12,8 +12,6 @@ #![feature(non_ascii_idents)] -use std::num::Float; - pub fn main() { let ε = 0.00001f64; let Π = 3.14f64; diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index d81dc3afcd..fd70c0409f 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc, std_misc)] diff --git a/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs b/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs index e21ea025d8..af06fe3813 100644 --- a/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs +++ b/src/test/run-pass/variance-intersection-of-ref-and-opt-ref.rs @@ -13,7 +13,6 @@ // us from approximating the lifetimes of `field1` and `field2` to a // common intersection. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(core)] diff --git a/src/test/run-pass/variance-trait-matching.rs b/src/test/run-pass/variance-trait-matching.rs deleted file mode 100644 index 5a179bfc7d..0000000000 --- a/src/test/run-pass/variance-trait-matching.rs +++ /dev/null @@ -1,49 +0,0 @@ -// 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. - -// pretty-expanded FIXME #23616 - -#![allow(dead_code)] - -// Get is covariant in T -trait Get { - fn get(&self) -> T; -} - -struct Cloner { - t: T -} - -impl Get for Cloner { - fn get(&self) -> T { - self.t.clone() - } -} - -fn get<'a, G>(get: &G) -> i32 - where G : Get<&'a i32> -{ - // This call only type checks if we can use `G : Get<&'a i32>` as - // evidence that `G : Get<&'b i32>` where `'a : 'b`. - pick(get, &22) -} - -fn pick<'b, G>(get: &'b G, if_odd: &'b i32) -> i32 - where G : Get<&'b i32> -{ - let v = *get.get(); - if v % 2 != 0 { v } else { *if_odd } -} - -fn main() { - let x = Cloner { t: &23 }; - let y = get(&x); - assert_eq!(y, 23); -} diff --git a/src/test/run-pass/variance-vec-covariant.rs b/src/test/run-pass/variance-vec-covariant.rs index 2f554c3c4f..89927b7b55 100644 --- a/src/test/run-pass/variance-vec-covariant.rs +++ b/src/test/run-pass/variance-vec-covariant.rs @@ -10,7 +10,6 @@ // Test that vec is now covariant in its argument type. -// pretty-expanded FIXME #23616 #![allow(dead_code)] #![feature(core)] diff --git a/src/test/run-pass/vec-dst.rs b/src/test/run-pass/vec-dst.rs index e88acb3838..223907c01b 100644 --- a/src/test/run-pass/vec-dst.rs +++ b/src/test/run-pass/vec-dst.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index 4dadf53c77..fbaba9b8a6 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::mem::size_of; diff --git a/src/test/run-pass/vec-growth.rs b/src/test/run-pass/vec-growth.rs index d5e6a9c424..e51d898e1d 100644 --- a/src/test/run-pass/vec-growth.rs +++ b/src/test/run-pass/vec-growth.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut v = vec!(1); diff --git a/src/test/run-pass/vec-macro-repeat.rs b/src/test/run-pass/vec-macro-repeat.rs index 2a83ccaba8..d178041b85 100644 --- a/src/test/run-pass/vec-macro-repeat.rs +++ b/src/test/run-pass/vec-macro-repeat.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(vec![1; 3], vec![1, 1, 1]); diff --git a/src/test/run-pass/vec-macro-rvalue-scope.rs b/src/test/run-pass/vec-macro-rvalue-scope.rs index 5869558eac..305755347d 100644 --- a/src/test/run-pass/vec-macro-rvalue-scope.rs +++ b/src/test/run-pass/vec-macro-rvalue-scope.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 fn one() -> i32 { 1 } diff --git a/src/test/run-pass/vec-macro-with-trailing-comma.rs b/src/test/run-pass/vec-macro-with-trailing-comma.rs index 3018a746b4..35af249ef5 100644 --- a/src/test/run-pass/vec-macro-with-trailing-comma.rs +++ b/src/test/run-pass/vec-macro-with-trailing-comma.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(vec!(1), vec!(1,)); diff --git a/src/test/run-pass/vec-matching-autoslice.rs b/src/test/run-pass/vec-matching-autoslice.rs index 2b80ad8103..5728424e32 100644 --- a/src/test/run-pass/vec-matching-autoslice.rs +++ b/src/test/run-pass/vec-matching-autoslice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching-fixed.rs b/src/test/run-pass/vec-matching-fixed.rs index 1278eaf96a..1ed6ddc411 100644 --- a/src/test/run-pass/vec-matching-fixed.rs +++ b/src/test/run-pass/vec-matching-fixed.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching-fold.rs b/src/test/run-pass/vec-matching-fold.rs index c375fc85bc..ee70ea5875 100644 --- a/src/test/run-pass/vec-matching-fold.rs +++ b/src/test/run-pass/vec-matching-fold.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index b81bdda613..eedf27f857 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(advanced_slice_patterns)] #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-slice-drop.rs b/src/test/run-pass/vec-slice-drop.rs index 1d749d4963..f400869682 100644 --- a/src/test/run-pass/vec-slice-drop.rs +++ b/src/test/run-pass/vec-slice-drop.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_destructor)] diff --git a/src/test/run-pass/vec-slice.rs b/src/test/run-pass/vec-slice.rs index 6baeb99df9..a7e6cae93b 100644 --- a/src/test/run-pass/vec-slice.rs +++ b/src/test/run-pass/vec-slice.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let v = vec![1,2,3,4,5]; diff --git a/src/test/run-pass/vec-tail-matching.rs b/src/test/run-pass/vec-tail-matching.rs index 091e3f03e7..75f970543a 100644 --- a/src/test/run-pass/vec-tail-matching.rs +++ b/src/test/run-pass/vec-tail-matching.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index a9bb68395c..f000ada770 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { assert_eq!(format!("{:?}", vec!(0, 1)), "[0, 1]".to_string()); diff --git a/src/test/run-pass/vec.rs b/src/test/run-pass/vec.rs index ce20d452c4..c61b3d56db 100644 --- a/src/test/run-pass/vec.rs +++ b/src/test/run-pass/vec.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let v: Vec = vec!(10, 20); diff --git a/src/test/run-pass/vector-sort-panic-safe.rs b/src/test/run-pass/vector-sort-panic-safe.rs index 09ecdf45b9..a51274199b 100644 --- a/src/test/run-pass/vector-sort-panic-safe.rs +++ b/src/test/run-pass/vector-sort-panic-safe.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rand, core)] use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -use std::rand::{thread_rng, Rng, Rand}; +use std::__rand::{thread_rng, Rng}; use std::thread; const REPEATS: usize = 5; @@ -37,18 +36,7 @@ static drop_counts: [AtomicUsize; MAX_LEN] = static creation_count: AtomicUsize = ATOMIC_USIZE_INIT; #[derive(Clone, PartialEq, PartialOrd, Eq, Ord)] -struct DropCounter { x: usize, creation_id: usize } - -impl Rand for DropCounter { - fn rand(rng: &mut R) -> DropCounter { - // (we're not using this concurrently, so Relaxed is fine.) - let num = creation_count.fetch_add(1, Ordering::Relaxed); - DropCounter { - x: rng.gen(), - creation_id: num - } - } -} +struct DropCounter { x: u32, creation_id: usize } impl Drop for DropCounter { fn drop(&mut self) { @@ -57,7 +45,7 @@ impl Drop for DropCounter { } pub fn main() { - assert!(MAX_LEN <= std::usize::BITS as usize); + assert!(MAX_LEN <= std::usize::BITS); // len can't go above 64. for len in 2..MAX_LEN { for _ in 0..REPEATS { @@ -65,9 +53,13 @@ pub fn main() { // IDs start from 0. creation_count.store(0, Ordering::Relaxed); - let main = thread_rng().gen_iter::() - .take(len) - .collect::>(); + let mut rng = thread_rng(); + let main = (0..len).map(|_| { + DropCounter { + x: rng.next_u32(), + creation_id: creation_count.fetch_add(1, Ordering::Relaxed), + } + }).collect::>(); // work out the total number of comparisons required to sort // this array... diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs index 079c97013a..1d0004bafa 100644 --- a/src/test/run-pass/wait-forked-but-failed-child.rs +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 -#![feature(libc, old_io)] +#![feature(libc)] extern crate libc; -use std::old_io::process::Command; +use std::process::Command; use libc::funcs::posix88::unistd; @@ -39,7 +38,7 @@ fn find_zombies() { // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html let ps_cmd_output = Command::new("ps").args(&["-A", "-o", "pid,ppid,args"]).output().unwrap(); - let ps_output = String::from_utf8_lossy(&ps_cmd_output.output); + let ps_output = String::from_utf8_lossy(&ps_cmd_output.stdout); for (line_no, line) in ps_output.split('\n').enumerate() { if 0 < line_no && 0 < line.len() && @@ -60,7 +59,7 @@ fn main() { let too_long = format!("/NoSuchCommand{:0300}", 0u8); let _failures = (0..100).map(|_| { - let cmd = Command::new(&too_long); + let mut cmd = Command::new(&too_long); let failed = cmd.spawn(); assert!(failed.is_err(), "Make sure the command fails to spawn(): {:?}", cmd); failed diff --git a/src/test/run-pass/where-for-self.rs b/src/test/run-pass/where-for-self.rs index 8535d76d47..1d477b8744 100644 --- a/src/test/run-pass/where-for-self.rs +++ b/src/test/run-pass/where-for-self.rs @@ -11,20 +11,14 @@ // Test that we can quantify lifetimes outside a constraint (i.e., including // the self type) in a where clause. -// pretty-expanded FIXME #23616 - -use std::marker::PhantomFn; static mut COUNT: u32 = 1; -trait Bar<'a> - : PhantomFn<&'a ()> -{ +trait Bar<'a> { fn bar(&self); } trait Baz<'a> - : PhantomFn<&'a ()> { fn baz(&self); } diff --git a/src/test/run-pass/while-label.rs b/src/test/run-pass/while-label.rs index 076ba8f428..8cbb845836 100644 --- a/src/test/run-pass/while-label.rs +++ b/src/test/run-pass/while-label.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 pub fn main() { let mut i = 100; diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs index b1e80c86ec..5a2ecdd45d 100644 --- a/src/test/run-pass/while-let.rs +++ b/src/test/run-pass/while-let.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(collections)] diff --git a/src/test/run-pass/while-prelude-drop.rs b/src/test/run-pass/while-prelude-drop.rs index 88d5314a96..7ff7703277 100644 --- a/src/test/run-pass/while-prelude-drop.rs +++ b/src/test/run-pass/while-prelude-drop.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![feature(collections)] use std::string::String; diff --git a/src/test/run-pass/writealias.rs b/src/test/run-pass/writealias.rs index 10718e981f..7339fe47dc 100644 --- a/src/test/run-pass/writealias.rs +++ b/src/test/run-pass/writealias.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 use std::sync::Mutex; diff --git a/src/test/run-pass/x86stdcall2.rs b/src/test/run-pass/x86stdcall2.rs index 7b15531dac..62da9c9d14 100644 --- a/src/test/run-pass/x86stdcall2.rs +++ b/src/test/run-pass/x86stdcall2.rs @@ -10,6 +10,8 @@ // pretty-expanded FIXME #23616 +#![feature(std_misc)] + pub type HANDLE = u32; pub type DWORD = u32; pub type SIZE_T = u32; diff --git a/src/test/run-pass/xcrate-address-insignificant.rs b/src/test/run-pass/xcrate-address-insignificant.rs index ac8b15d7bf..8794ecd061 100644 --- a/src/test/run-pass/xcrate-address-insignificant.rs +++ b/src/test/run-pass/xcrate-address-insignificant.rs @@ -10,7 +10,6 @@ // aux-build:xcrate_address_insignificant.rs -// pretty-expanded FIXME #23616 extern crate xcrate_address_insignificant as foo; diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs index dea9edf058..a80faeaea7 100644 --- a/src/test/run-pass/zero-size-type-destructors.rs +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(unsafe_no_drop_flag)] diff --git a/src/test/run-pass/zero_sized_subslice_match.rs b/src/test/run-pass/zero_sized_subslice_match.rs index b98f907774..697508ae48 100644 --- a/src/test/run-pass/zero_sized_subslice_match.rs +++ b/src/test/run-pass/zero_sized_subslice_match.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(slice_patterns)] diff --git a/src/test/run-make/rustdoc-assoc-types/lib.rs b/src/test/rustdoc/assoc-types.rs similarity index 95% rename from src/test/run-make/rustdoc-assoc-types/lib.rs rename to src/test/rustdoc/assoc-types.rs index 3e6e0ad560..20076a7649 100644 --- a/src/test/run-make/rustdoc-assoc-types/lib.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -10,7 +10,7 @@ #![crate_type="lib"] -// @has lib/trait.Index.html +// @has assoc_types/trait.Index.html pub trait Index { // @has - '//*[@id="associatedtype.Output"]//code' 'type Output: ?Sized' type Output: ?Sized; diff --git a/src/test/run-make/rustdoc-ffi/user.rs b/src/test/rustdoc/default-impl.rs similarity index 76% rename from src/test/run-make/rustdoc-ffi/user.rs rename to src/test/rustdoc/default-impl.rs index 09d7a7c536..92b2431400 100644 --- a/src/test/run-make/rustdoc-ffi/user.rs +++ b/src/test/rustdoc/default-impl.rs @@ -8,9 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type="lib"] +// aux-build:rustdoc-default-impl.rs +// ignore-android -extern crate lib; +extern crate rustdoc_default_impl as foo; -// @has user/fn.foreigner.html //pre 'pub unsafe fn foreigner(cold_as_ice: u32)' -pub use lib::foreigner; +pub use foo::bar; + +pub fn wut() { +} diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs new file mode 100644 index 0000000000..9178c1bcb9 --- /dev/null +++ b/src/test/rustdoc/extern-default-method.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:rustdoc-extern-default-method.rs +// ignore-android + +extern crate rustdoc_extern_default_method as ext; + +// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1 +pub use ext::Struct; diff --git a/src/test/run-make/rustdoc-extern-method/bar.rs b/src/test/rustdoc/extern-method.rs similarity index 74% rename from src/test/run-make/rustdoc-extern-method/bar.rs rename to src/test/rustdoc/extern-method.rs index 26a05f8490..5e30e6c0c1 100644 --- a/src/test/run-make/rustdoc-extern-method/bar.rs +++ b/src/test/rustdoc/extern-method.rs @@ -8,16 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:rustdoc-extern-method.rs +// ignore-android + #![feature(unboxed_closures)] -extern crate foo; +extern crate rustdoc_extern_method as foo; -// @has bar/trait.Foo.html //pre "pub trait Foo" +// @has extern_method/trait.Foo.html //pre "pub trait Foo" // @has - '//*[@id="tymethod.foo"]//code' 'extern "rust-call" fn foo' -// @has - '//*[@id="tymethod.foo_"]//code' 'extern "rust-call" fn foo_' +// @has - '//*[@id="method.foo_"]//code' 'extern "rust-call" fn foo_' pub use foo::Foo; -// @has bar/trait.Bar.html //pre "pub trait Bar" +// @has extern_method/trait.Bar.html //pre "pub trait Bar" pub trait Bar { // @has - '//*[@id="tymethod.bar"]//code' 'extern "rust-call" fn bar' extern "rust-call" fn bar(&self, _: ()); diff --git a/src/test/rustdoc/ffi.rs b/src/test/rustdoc/ffi.rs new file mode 100644 index 0000000000..717c64b3aa --- /dev/null +++ b/src/test/rustdoc/ffi.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:rustdoc-ffi.rs +// ignore-android + +extern crate rustdoc_ffi as lib; + +// @has ffi/fn.foreigner.html //pre 'pub unsafe extern fn foreigner(cold_as_ice: u32)' +pub use lib::foreigner; + +extern "C" { + // @has ffi/fn.another.html //pre 'pub unsafe extern fn another(cold_as_ice: u32)' + pub fn another(cold_as_ice: u32); +} diff --git a/src/test/run-make/rustdoc-hidden-line/foo.rs b/src/test/rustdoc/hidden-line.rs similarity index 94% rename from src/test/run-make/rustdoc-hidden-line/foo.rs rename to src/test/rustdoc/hidden-line.rs index 3906d9ee8a..bb9eec793d 100644 --- a/src/test/run-make/rustdoc-hidden-line/foo.rs +++ b/src/test/rustdoc/hidden-line.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_name="foo"] - /// The '# ' lines should be removed from the output, but the #[derive] should be /// retained. /// @@ -31,5 +29,5 @@ /// ``` pub fn foo() {} -// @!has foo/fn.foo.html invisible +// @!has hidden_line/fn.foo.html invisible // @matches - //pre "#\[derive\(PartialEq\)\] // Bar" diff --git a/src/test/rustdoc/inline-default-methods.rs b/src/test/rustdoc/inline-default-methods.rs new file mode 100644 index 0000000000..a613736ab4 --- /dev/null +++ b/src/test/rustdoc/inline-default-methods.rs @@ -0,0 +1,19 @@ +// 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. + +// aux-build:inline-default-methods.rs +// ignore-android + +extern crate inline_default_methods; + +// @has inline_default_methods/trait.Foo.html +// @has - '//*[@class="rust trait"]' 'fn bar(&self);' +// @has - '//*[@class="rust trait"]' 'fn foo(&mut self) { ... }' +pub use inline_default_methods::Foo; diff --git a/src/test/rustdoc/issue-13698.rs b/src/test/rustdoc/issue-13698.rs new file mode 100644 index 0000000000..5c31c29772 --- /dev/null +++ b/src/test/rustdoc/issue-13698.rs @@ -0,0 +1,26 @@ +// 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. + +// aux-build:issue-13698.rs +// ignore-android + +extern crate issue_13698; + +pub struct Foo; +// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn foo' +impl issue_13698::Foo for Foo {} + +pub trait Bar { + #[doc(hidden)] + fn bar(&self) {} +} + +// @!has issue_13698/struct.Foo.html '//*[@id="method.foo"]' 'fn bar' +impl Bar for Foo {} diff --git a/src/test/rustdoc/issue-15169.rs b/src/test/rustdoc/issue-15169.rs new file mode 100644 index 0000000000..6ab848b92d --- /dev/null +++ b/src/test/rustdoc/issue-15169.rs @@ -0,0 +1,13 @@ +// 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. + +// @has issue_15169/struct.Foo.html '//*[@id="method.eq"]' 'fn eq' +#[derive(PartialEq)] +pub struct Foo; diff --git a/src/test/rustdoc/issue-15318-2.rs b/src/test/rustdoc/issue-15318-2.rs new file mode 100644 index 0000000000..32898d652f --- /dev/null +++ b/src/test/rustdoc/issue-15318-2.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:issue-15318.rs +// ignore-android + +extern crate issue_15318; + +pub use issue_15318::ptr; + +// @has issue_15318_2/fn.bar.html \ +// '//*[@href="primitive.pointer.html"]' \ +// '*mut T' +pub fn bar(ptr: *mut T) {} + diff --git a/src/test/rustdoc/issue-15318-3.rs b/src/test/rustdoc/issue-15318-3.rs new file mode 100644 index 0000000000..a54824970c --- /dev/null +++ b/src/test/rustdoc/issue-15318-3.rs @@ -0,0 +1,15 @@ +// 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. + +// @has issue_15318_3/primitive.pointer.html + +/// dox +#[doc(primitive = "pointer")] +pub mod ptr {} diff --git a/src/test/rustdoc/issue-15318.rs b/src/test/rustdoc/issue-15318.rs new file mode 100644 index 0000000000..3bcc8f45b0 --- /dev/null +++ b/src/test/rustdoc/issue-15318.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:issue-15318.rs +// ignore-android + +#![feature(no_std)] +#![no_std] + +extern crate issue_15318; + +// @has issue_15318/fn.bar.html \ +// '//*[@href="http://example.com/issue_15318/primitive.pointer.html"]' \ +// '*mut T' +pub fn bar(ptr: *mut T) {} diff --git a/src/test/rustdoc/issue-15347.rs b/src/test/rustdoc/issue-15347.rs new file mode 100644 index 0000000000..97c37bbc1e --- /dev/null +++ b/src/test/rustdoc/issue-15347.rs @@ -0,0 +1,15 @@ +// Copyright 2105 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. + +// compile-flags:--no-defaults --passes "collapse-docs" --passes "unindent-comments" + +// @has issue_15347/fn.foo.html +#[doc(hidden)] +pub fn foo() {} diff --git a/src/test/rustdoc/issue-16019.rs b/src/test/rustdoc/issue-16019.rs new file mode 100644 index 0000000000..7aae6a0595 --- /dev/null +++ b/src/test/rustdoc/issue-16019.rs @@ -0,0 +1,19 @@ +// 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. + +macro_rules! define_struct { + ($rounds:expr) => ( + struct Struct { + sk: [u32; $rounds + 1] + } + ) +} + +define_struct!(2); diff --git a/src/test/rustdoc/issue-16265-1.rs b/src/test/rustdoc/issue-16265-1.rs new file mode 100644 index 0000000000..c0b99a627e --- /dev/null +++ b/src/test/rustdoc/issue-16265-1.rs @@ -0,0 +1,18 @@ +// 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. + +pub struct Foo; + +// @has issue_16265_1/traits/index.html '[src]' +pub mod traits { + impl PartialEq for super::Foo { + fn eq(&self, _: &super::Foo) -> bool { true } + } +} diff --git a/src/test/rustdoc/issue-16265-2.rs b/src/test/rustdoc/issue-16265-2.rs new file mode 100644 index 0000000000..22a8df407e --- /dev/null +++ b/src/test/rustdoc/issue-16265-2.rs @@ -0,0 +1,15 @@ +// 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. + + +// @has issue_16265_2/index.html '[src]' + +trait Y {} +impl Y for Option{} diff --git a/src/test/rustdoc/issue-17476.rs b/src/test/rustdoc/issue-17476.rs new file mode 100644 index 0000000000..8d31a1c288 --- /dev/null +++ b/src/test/rustdoc/issue-17476.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:issue-17476.rs +// ignore-android + +extern crate issue_17476; + +pub struct Foo; + +// @has issue_17476/struct.Foo.html \ +// '//*[@href="http://example.com/issue_17476/trait.Foo.html#method.foo"]' \ +// 'foo' +impl issue_17476::Foo for Foo {} diff --git a/src/test/rustdoc/issue-18199.rs b/src/test/rustdoc/issue-18199.rs new file mode 100644 index 0000000000..46aac8701f --- /dev/null +++ b/src/test/rustdoc/issue-18199.rs @@ -0,0 +1,19 @@ +// 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. + +// compile-flags:--test + +#![doc(test(attr(feature(staged_api))))] + +/// ``` +/// #![staged_api] +/// fn main() {} +/// ``` +pub fn foo() {} diff --git a/src/test/rustdoc/issue-19055.rs b/src/test/rustdoc/issue-19055.rs new file mode 100644 index 0000000000..609ae22be1 --- /dev/null +++ b/src/test/rustdoc/issue-19055.rs @@ -0,0 +1,30 @@ +// 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. + +// @has issue_19055/trait.Any.html +pub trait Any {} + +impl<'any> Any + 'any { + // @has - '//*[@id="method.is"]' 'fn is' + pub fn is(&self) -> bool { loop {} } + + // @has - '//*[@id="method.downcast_ref"]' 'fn downcast_ref' + pub fn downcast_ref(&self) -> Option<&T> { loop {} } + + // @has - '//*[@id="method.downcast_mut"]' 'fn downcast_mut' + pub fn downcast_mut(&mut self) -> Option<&mut T> { loop {} } +} + +pub trait Foo { + fn foo(&self) {} +} + +// @has - '//*[@id="method.foo"]' 'fn foo' +impl Foo for Any {} diff --git a/src/test/rustdoc/issue-20175.rs b/src/test/rustdoc/issue-20175.rs new file mode 100644 index 0000000000..33ec4b75c4 --- /dev/null +++ b/src/test/rustdoc/issue-20175.rs @@ -0,0 +1,20 @@ +// 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. + +pub trait Foo { + fn foo(&self) {} +} + +pub struct Bar; + +// @has issue_20175/struct.Bar.html \ +// '//*[@id="method.foo"]' \ +// 'fn foo' +impl<'a> Foo for &'a Bar {} diff --git a/src/test/rustdoc/issue-20646.rs b/src/test/rustdoc/issue-20646.rs new file mode 100644 index 0000000000..77abe35948 --- /dev/null +++ b/src/test/rustdoc/issue-20646.rs @@ -0,0 +1,36 @@ +// 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. + +// aux-build:issue-20646.rs +// ignore-android + +#![feature(associated_types)] + +extern crate issue_20646; + +// @has issue_20646/trait.Trait.html \ +// '//*[@id="associatedtype.Output"]' \ +// 'type Output' +pub trait Trait { + type Output; +} + +// @has issue_20646/fn.fun.html \ +// '//*[@class="rust fn"]' 'where T: Trait' +pub fn fun(_: T) where T: Trait {} + +pub mod reexport { + // @has issue_20646/reexport/trait.Trait.html \ + // '//*[@id="associatedtype.Output"]' \ + // 'type Output' + // @has issue_20646/reexport/fn.fun.html \ + // '//*[@class="rust fn"]' 'where T: Trait' + pub use issue_20646::{Trait, fun}; +} diff --git a/src/test/rustdoc/issue-20727-2.rs b/src/test/rustdoc/issue-20727-2.rs new file mode 100644 index 0000000000..03181bebdb --- /dev/null +++ b/src/test/rustdoc/issue-20727-2.rs @@ -0,0 +1,33 @@ +// 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. + +// aux-build:issue-20727.rs +// ignore-android + +extern crate issue_20727; + +// @has issue_20727_2/trait.Add.html +pub trait Add { + // @has - '//*[@class="rust trait"]' 'trait Add {' + // @has - '//*[@class="rust trait"]' 'type Output;' + type Output; + + // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;' + fn add(self, rhs: RHS) -> Self::Output; +} + +// @has issue_20727_2/reexport/trait.Add.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Add {' + // @has - '//*[@class="rust trait"]' 'type Output;' + // @has - '//*[@class="rust trait"]' 'fn add(self, rhs: RHS) -> Self::Output;' + pub use issue_20727::Add; +} + diff --git a/src/test/rustdoc/issue-20727-3.rs b/src/test/rustdoc/issue-20727-3.rs new file mode 100644 index 0000000000..9d05ce99c4 --- /dev/null +++ b/src/test/rustdoc/issue-20727-3.rs @@ -0,0 +1,34 @@ +// 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. + +// aux-build:issue-20727.rs +// ignore-android + +extern crate issue_20727; + +pub trait Bar {} + +// @has issue_20727_3/trait.Deref2.html +pub trait Deref2 { + // @has - '//*[@class="rust trait"]' 'trait Deref2 {' + // @has - '//*[@class="rust trait"]' 'type Target: Bar;' + type Target: Bar; + + // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;' + fn deref(&self) -> Self::Target; +} + +// @has issue_20727_3/reexport/trait.Deref2.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Deref2 {' + // @has - '//*[@class="rust trait"]' 'type Target: Bar;' + // @has - '//*[@class="rust trait"]' 'fn deref(&self) -> Self::Target;' + pub use issue_20727::Deref2; +} diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs new file mode 100644 index 0000000000..39db387f09 --- /dev/null +++ b/src/test/rustdoc/issue-20727-4.rs @@ -0,0 +1,50 @@ +// 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. + +// aux-build:issue-20727.rs +// ignore-android + +extern crate issue_20727; + +// @has issue_20727_4/trait.Index.html +pub trait Index { + // @has - '//*[@class="rust trait"]' 'trait Index {' + // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' + type Output: ?Sized; + + // @has - '//*[@class="rust trait"]' \ + // 'fn index(&self, index: Idx) -> &Self::Output' + fn index(&self, index: Idx) -> &Self::Output; +} + +// @has issue_20727_4/trait.IndexMut.html +pub trait IndexMut: Index { + // @has - '//*[@class="rust trait"]' \ + // 'trait IndexMut: Index {' + // @has - '//*[@class="rust trait"]' \ + // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' + fn index_mut(&mut self, index: Idx) -> &mut Self::Output; +} + +pub mod reexport { + // @has issue_20727_4/reexport/trait.Index.html + // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized {' + // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' + // @has - '//*[@class="rust trait"]' \ + // 'fn index(&self, index: Idx) -> &Self::Output' + pub use issue_20727::Index; + + // @has issue_20727_4/reexport/trait.IndexMut.html + // @has - '//*[@class="rust trait"]' \ + // 'trait IndexMut: Index where Idx: ?Sized {' + // @has - '//*[@class="rust trait"]' \ + // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' + pub use issue_20727::IndexMut; +} diff --git a/src/test/rustdoc/issue-20727.rs b/src/test/rustdoc/issue-20727.rs new file mode 100644 index 0000000000..3205f5bfa3 --- /dev/null +++ b/src/test/rustdoc/issue-20727.rs @@ -0,0 +1,34 @@ +// 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. + +// aux-build:issue-20727.rs +// ignore-android + +extern crate issue_20727; + +// @has issue_20727/trait.Deref.html +pub trait Deref { + // @has - '//*[@class="rust trait"]' 'trait Deref {' + // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;' + type Target: ?Sized; + + // @has - '//*[@class="rust trait"]' \ + // "fn deref<'a>(&'a self) -> &'a Self::Target;" + fn deref<'a>(&'a self) -> &'a Self::Target; +} + +// @has issue_20727/reexport/trait.Deref.html +pub mod reexport { + // @has - '//*[@class="rust trait"]' 'trait Deref {' + // @has - '//*[@class="rust trait"]' 'type Target: ?Sized;' + // @has - '//*[@class="rust trait"]' \ + // "fn deref(&'a self) -> &'a Self::Target;" + pub use issue_20727::Deref; +} diff --git a/src/test/rustdoc/issue-21092.rs b/src/test/rustdoc/issue-21092.rs new file mode 100644 index 0000000000..38983aee93 --- /dev/null +++ b/src/test/rustdoc/issue-21092.rs @@ -0,0 +1,18 @@ +// 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. + +// aux-build:issue-21092.rs +// ignore-android + +extern crate issue_21092; + +// @has issue_21092/struct.Bar.html +// @has - '//*[@id="assoc_type.Bar"]' 'type Bar = i32' +pub use issue_21092::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs new file mode 100644 index 0000000000..36f160acf1 --- /dev/null +++ b/src/test/rustdoc/issue-21474.rs @@ -0,0 +1,21 @@ +// Copyright 2012-2014 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. + +pub use inner::*; + +mod inner { + impl super::Blah for super::What { } +} + +pub trait Blah { } + +// @count issue_21474/struct.What.html \ +// '//*[@class="impl"]' 1 +pub struct What; diff --git a/src/test/rustdoc/issue-21801.rs b/src/test/rustdoc/issue-21801.rs new file mode 100644 index 0000000000..a4392b84e5 --- /dev/null +++ b/src/test/rustdoc/issue-21801.rs @@ -0,0 +1,19 @@ +// 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. + +// aux-build:issue-21801.rs +// ignore-android + +extern crate issue_21801; + +// @has issue_21801/struct.Foo.html +// @has - '//*[@id="method.new"]' \ +// 'fn new(f: F) -> Foo where F: FnMut() -> i32' +pub use issue_21801::Foo; diff --git a/src/test/rustdoc/issue-22025.rs b/src/test/rustdoc/issue-22025.rs new file mode 100644 index 0000000000..d2eb4fb6ad --- /dev/null +++ b/src/test/rustdoc/issue-22025.rs @@ -0,0 +1,16 @@ +// 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. + +// aux-build:issue-22025.rs +// ignore-android + +extern crate issue_22025; + +pub use issue_22025::foo::{Foo, Bar}; diff --git a/src/test/rustdoc/issue-22038.rs b/src/test/rustdoc/issue-22038.rs new file mode 100644 index 0000000000..6f84428b07 --- /dev/null +++ b/src/test/rustdoc/issue-22038.rs @@ -0,0 +1,29 @@ +// 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. + +extern { + // @has issue_22038/fn.foo1.html \ + // '//*[@class="rust fn"]' 'pub unsafe extern fn foo1()' + pub fn foo1(); +} + +extern "system" { + // @has issue_22038/fn.foo2.html \ + // '//*[@class="rust fn"]' 'pub unsafe extern "system" fn foo2()' + pub fn foo2(); +} + +// @has issue_22038/fn.bar.html \ +// '//*[@class="rust fn"]' 'pub extern fn bar()' +pub extern fn bar() {} + +// @has issue_22038/fn.baz.html \ +// '//*[@class="rust fn"]' 'pub extern "system" fn baz()' +pub extern "system" fn baz() {} diff --git a/src/test/rustdoc/issue-23106.rs b/src/test/rustdoc/issue-23106.rs new file mode 100644 index 0000000000..bfafc6be67 --- /dev/null +++ b/src/test/rustdoc/issue-23106.rs @@ -0,0 +1,17 @@ +// 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. + +// compile-flags:--test + +/// ``` +/// # +/// ``` +pub fn main() { +} diff --git a/src/test/rustdoc/issue-23207.rs b/src/test/rustdoc/issue-23207.rs new file mode 100644 index 0000000000..722046723b --- /dev/null +++ b/src/test/rustdoc/issue-23207.rs @@ -0,0 +1,20 @@ +// 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. + +// aux-build:issue-23207-1.rs +// aux-build:issue-23207-2.rs +// ignore-android + +extern crate issue_23207_2; + +// @has issue_23207/fmt/index.html +// @count - '//*[@class="struct"]' 1 +pub use issue_23207_2::fmt; + diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs new file mode 100644 index 0000000000..6582ca0eba --- /dev/null +++ b/src/test/rustdoc/issue-23511.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(no_std, lang_items, core)] +#![no_std] + +extern crate core; + +pub mod str { + #![doc(primitive = "str")] + + #[lang = "str"] + impl str { + // @has search-index.js foo + pub fn foo(&self) {} + } +} diff --git a/src/test/rustdoc/issue-23744.rs b/src/test/rustdoc/issue-23744.rs new file mode 100644 index 0000000000..25374ac0c7 --- /dev/null +++ b/src/test/rustdoc/issue-23744.rs @@ -0,0 +1,22 @@ +// 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. + +// compile-flags:--test + +/// Example of rustdoc incorrectly parsing ```rust,should_panic. +/// +/// ```should_panic +/// fn main() { panic!("fee"); } +/// ``` +/// +/// ```rust,should_panic +/// fn main() { panic!("fum"); } +/// ``` +pub fn foo() {} diff --git a/src/test/run-make/rustdoc-must-use/lib.rs b/src/test/rustdoc/must-use.rs similarity index 81% rename from src/test/run-make/rustdoc-must-use/lib.rs rename to src/test/rustdoc/must-use.rs index cef79d4536..e293675f5b 100644 --- a/src/test/run-make/rustdoc-must-use/lib.rs +++ b/src/test/rustdoc/must-use.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_type="lib"] - -// @has lib/struct.Struct.html //pre '#[must_use]' +// @has must_use/struct.Struct.html //pre '#[must_use]' #[must_use] pub struct Struct { field: i32, } -// @has lib/enum.Enum.html //pre '#[must_use = "message"]' +// @has must_use/enum.Enum.html //pre '#[must_use = "message"]' #[must_use = "message"] pub enum Enum { Variant(i32), diff --git a/src/test/run-make/rustdoc-negative-impl/foo.rs b/src/test/rustdoc/negative-impl.rs similarity index 63% rename from src/test/run-make/rustdoc-negative-impl/foo.rs rename to src/test/rustdoc/negative-impl.rs index 6c56bcc9be..aadabb15d1 100644 --- a/src/test/run-make/rustdoc-negative-impl/foo.rs +++ b/src/test/rustdoc/negative-impl.rs @@ -10,13 +10,13 @@ #![feature(optin_builtin_traits)] -// @matches foo/struct.Alpha.html '//pre' "pub struct Alpha" +// @matches negative_impl/struct.Alpha.html '//pre' "pub struct Alpha" pub struct Alpha; -// @matches foo/struct.Bravo.html '//pre' "pub struct Bravo" +// @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo" pub struct Bravo(B); -// @matches foo/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha" +// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha" impl !Send for Alpha {} -// @matches foo/struct.Bravo.html '//*[@class="impl"]//code' "impl !Send for Bravo" +// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl !Send for Bravo" impl !Send for Bravo {} diff --git a/src/test/run-make/rustdoc-recursion/foo.rs b/src/test/rustdoc/recursion1.rs similarity index 100% rename from src/test/run-make/rustdoc-recursion/foo.rs rename to src/test/rustdoc/recursion1.rs diff --git a/src/test/run-make/rustdoc-recursion/foo2.rs b/src/test/rustdoc/recursion2.rs similarity index 100% rename from src/test/run-make/rustdoc-recursion/foo2.rs rename to src/test/rustdoc/recursion2.rs diff --git a/src/test/run-make/rustdoc-recursion/foo3.rs b/src/test/rustdoc/recursion3.rs similarity index 100% rename from src/test/run-make/rustdoc-recursion/foo3.rs rename to src/test/rustdoc/recursion3.rs diff --git a/src/test/run-make/rustdoc-search-index/index.rs b/src/test/rustdoc/search-index.rs similarity index 100% rename from src/test/run-make/rustdoc-search-index/index.rs rename to src/test/rustdoc/search-index.rs diff --git a/src/test/run-make/rustdoc-smoke/foo.rs b/src/test/rustdoc/smoke.rs similarity index 74% rename from src/test/run-make/rustdoc-smoke/foo.rs rename to src/test/rustdoc/smoke.rs index 494eb03d72..6ba7018bf2 100644 --- a/src/test/run-make/rustdoc-smoke/foo.rs +++ b/src/test/rustdoc/smoke.rs @@ -8,29 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// @has foo/index.html -#![crate_name = "foo"] +// @has smoke/index.html //! Very docs -// @has foo/bar/index.html +// @has smoke/bar/index.html pub mod bar { /// So correct - // @has foo/bar/baz/index.html + // @has smoke/bar/baz/index.html pub mod baz { /// Much detail - // @has foo/bar/baz/fn.baz.html + // @has smoke/bar/baz/fn.baz.html pub fn baz() { } } /// *wow* - // @has foo/bar/trait.Doge.html + // @has smoke/bar/trait.Doge.html pub trait Doge { fn dummy(&self) { } } - // @has foo/bar/struct.Foo.html + // @has smoke/bar/struct.Foo.html pub struct Foo { x: isize, y: usize } - // @has foo/bar/fn.prawns.html + // @has smoke/bar/fn.prawns.html pub fn prawns((a, b): (isize, usize), Foo { x, y }: Foo) { } } diff --git a/src/test/rustdoc/src-links.rs b/src/test/rustdoc/src-links.rs new file mode 100644 index 0000000000..4d7dad64b4 --- /dev/null +++ b/src/test/rustdoc/src-links.rs @@ -0,0 +1,56 @@ +// 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. + +#![crate_name = "foo"] + +//! Dox +// @has src/foo/src-links.rs.html +// @has foo/index.html '//a/@href' '../src/foo/src-links.rs.html' + +#[path = "src-links/mod.rs"] +pub mod qux; + +// @has foo/bar/index.html '//a/@href' '../../src/foo/src-links.rs.html' +pub mod bar { + + /// Dox + // @has foo/bar/baz/index.html '//a/@href' '../../../src/foo/src-links.rs.html' + pub mod baz { + /// Dox + // @has foo/bar/baz/fn.baz.html '//a/@href' '../../../src/foo/src-links.rs.html' + pub fn baz() { } + } + + /// Dox + // @has foo/bar/trait.Foobar.html '//a/@href' '../../src/foo/src-links.rs.html' + pub trait Foobar { fn dummy(&self) { } } + + // @has foo/bar/struct.Foo.html '//a/@href' '../../src/foo/src-links.rs.html' + pub struct Foo { x: i32, y: u32 } + + // @has foo/bar/fn.prawns.html '//a/@href' '../../src/foo/src-links.rs.html' + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +// @has foo/fn.modfn.html '//a/@href' '../src/foo/src-links.rs.html' +pub fn modfn() { } + +// same hierarchy as above, but just for the submodule + +// @has src/foo/src-links/mod.rs.html +// @has foo/qux/index.html '//a/@href' '../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/index.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/baz/index.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/baz/fn.baz.html '//a/@href' '../../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/trait.Foobar.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/struct.Foo.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/bar/fn.prawns.html '//a/@href' '../../../src/foo/src-links/mod.rs.html' +// @has foo/qux/fn.modfn.html '//a/@href' '../../src/foo/src-links/mod.rs.html' diff --git a/src/test/rustdoc/src-links/mod.rs b/src/test/rustdoc/src-links/mod.rs new file mode 100644 index 0000000000..eb5e737b36 --- /dev/null +++ b/src/test/rustdoc/src-links/mod.rs @@ -0,0 +1,29 @@ +// 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. + +//! Dox +pub mod bar { + + /// Dox + pub mod baz { + /// Dox + pub fn baz() { } + } + + /// Dox + pub trait Foobar { fn dummy(&self) { } } + + pub struct Foo { x: i32, y: u32 } + + pub fn prawns((a, b): (i32, u32), Foo { x, y }: Foo) { } +} + +/// Dox +pub fn modfn() { } diff --git a/src/test/run-make/rustdoc-viewpath-self/foo.rs b/src/test/rustdoc/viewpath-self.rs similarity index 97% rename from src/test/run-make/rustdoc-viewpath-self/foo.rs rename to src/test/rustdoc/viewpath-self.rs index 6fd47d84c3..65a981353f 100644 --- a/src/test/run-make/rustdoc-viewpath-self/foo.rs +++ b/src/test/rustdoc/viewpath-self.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![crate_name = "foo"] + pub mod io { pub trait Reader { fn dummy(&self) { } } } diff --git a/src/test/run-make/rustdoc-where/foo.rs b/src/test/rustdoc/where.rs similarity index 98% rename from src/test/run-make/rustdoc-where/foo.rs rename to src/test/rustdoc/where.rs index 91a7e1c9fd..3ce91d6330 100644 --- a/src/test/run-make/rustdoc-where/foo.rs +++ b/src/test/rustdoc/where.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![crate_name = "foo"] + pub trait MyTrait { fn dummy(&self) { } } // @has foo/struct.Alpha.html '//pre' "pub struct Alpha where A: MyTrait" -- 2.39.2

(path: P, timeout: Duration) - -> IoResult - where P: BytesContainer { - if timeout <= Duration::milliseconds(0) { - return Err(standard_error(TimedOut)); - } - - let path = try!(CString::new(path.container_as_bytes())); - UnixStreamImp::connect(&path, Some(timeout.num_milliseconds() as u64)) - .map(|inner| UnixStream { inner: inner }) - } - - - /// Closes the reading half of this connection. - /// - /// This method will close the reading portion of this connection, causing - /// all pending and future reads to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { - self.inner.close_read() - } - - /// Closes the writing half of this connection. - /// - /// This method will close the writing portion of this connection, causing - /// all pending and future writes to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { - self.inner.close_write() - } - - /// Sets the read/write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.inner.set_timeout(timeout_ms) - } - - /// Sets the read timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { - self.inner.set_read_timeout(timeout_ms) - } - - /// Sets the write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { - self.inner.set_write_timeout(timeout_ms) - } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { - UnixStream { inner: self.inner.clone() } - } -} - -impl Reader for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for UnixStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.write(buf) - } -} - -impl sys_common::AsInner for UnixStream { - fn as_inner(&self) -> &UnixStreamImp { - &self.inner - } -} - -/// A value that can listen for incoming named pipe connection requests. -pub struct UnixListener { - /// The internal, opaque runtime Unix listener. - inner: UnixListenerImp, -} - -impl UnixListener { - /// Creates a new listener, ready to receive incoming connections on the - /// specified socket. The server will be named by `path`. - /// - /// This listener will be closed when it falls out of scope. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, io, old_path)] - /// # fn foo() { - /// use std::old_io::net::pipe::UnixListener; - /// use std::old_io::*; - /// use std::old_path::Path; - /// - /// let server = Path::new("/path/to/my/socket"); - /// let stream = UnixListener::bind(&server); - /// for mut client in stream.listen().incoming() { - /// client.write(&[1, 2, 3, 4]); - /// } - /// # } - /// ``` - pub fn bind(path: P) -> IoResult { - let path = try!(CString::new(path.container_as_bytes())); - UnixListenerImp::bind(&path) - .map(|inner| UnixListener { inner: inner }) - } -} - -impl Listener for UnixListener { - fn listen(self) -> IoResult { - self.inner.listen() - .map(|inner| UnixAcceptor { inner: inner }) - } -} - -impl sys_common::AsInner for UnixListener { - fn as_inner(&self) -> &UnixListenerImp { - &self.inner - } -} - -/// A value that can accept named pipe connections, returned from `listen()`. -pub struct UnixAcceptor { - /// The internal, opaque runtime Unix acceptor. - inner: UnixAcceptorImp -} - -impl UnixAcceptor { - /// Sets a timeout for this acceptor, after which accept() will no longer - /// block indefinitely. - /// - /// The argument specified is the amount of time, in milliseconds, into the - /// future after which all invocations of accept() will not block (and any - /// pending invocation will return). A value of `None` will clear any - /// existing timeout. - /// - /// When using this method, it is likely necessary to reset the timeout as - /// appropriate, the timeout specified is specific to this object, not - /// specific to the next request. - #[unstable(feature = "io", - reason = "the name and arguments to this function are likely \ - to change")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.inner.set_timeout(timeout_ms) - } - - /// Closes the accepting capabilities of this acceptor. - /// - /// This function has the same semantics as `TcpAcceptor::close_accept`, and - /// more information can be found in that documentation. - #[unstable(feature = "io")] - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.close_accept() - } -} - -impl Acceptor for UnixAcceptor { - type Connection = UnixStream; - fn accept(&mut self) -> IoResult { - self.inner.accept().map(|s| { - UnixStream { inner: s } - }) - } -} - -impl Clone for UnixAcceptor { - /// Creates a new handle to this unix acceptor, allowing for simultaneous - /// accepts. - /// - /// The underlying unix acceptor will not be closed until all handles to the - /// acceptor have been deallocated. Incoming connections will be received on - /// at most once acceptor, the same connection will not be accepted twice. - /// - /// The `close_accept` method will shut down *all* acceptors cloned from the - /// same original acceptor, whereas the `set_timeout` method only affects - /// the selector that it is called on. - /// - /// This function is useful for creating a handle to invoke `close_accept` - /// on to wake up any other task blocked in `accept`. - fn clone(&self) -> UnixAcceptor { - UnixAcceptor { inner: self.inner.clone() } - } -} - -impl sys_common::AsInner for UnixAcceptor { - fn as_inner(&self) -> &UnixAcceptorImp { - &self.inner - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use old_io::fs::PathExtensions; - use old_io::{EndOfFile, TimedOut, ShortWrite, IoError, ConnectionReset}; - use old_io::{NotConnected, BrokenPipe, FileNotFound, InvalidInput, OtherIoError}; - use old_io::{PermissionDenied, Acceptor, Listener}; - use old_io::{Reader, Writer}; - use old_io::test::*; - use super::*; - use sync::mpsc::channel; - use thread; - use time::Duration; - - pub fn smalltest(server: F, client: G) - where F : FnOnce(UnixStream), F : Send, - G : FnOnce(UnixStream), G : Send + 'static - { - let path1 = next_test_unix(); - let path2 = path1.clone(); - - let mut acceptor = UnixListener::bind(&path1).listen(); - - let _t = thread::spawn(move|| { - match UnixStream::connect(&path2) { - Ok(c) => client(c), - Err(e) => panic!("failed connect: {}", e), - } - }); - - match acceptor.accept() { - Ok(c) => server(c), - Err(e) => panic!("failed accept: {}", e), - } - } - - #[test] - fn bind_error() { - let path = "path/to/nowhere"; - match UnixListener::bind(&path) { - Ok(..) => panic!(), - Err(e) => { - assert!(e.kind == PermissionDenied || e.kind == FileNotFound || - e.kind == InvalidInput); - } - } - } - - #[test] - fn connect_error() { - let path = if cfg!(windows) { - r"\\.\pipe\this_should_not_exist_ever" - } else { - "path/to/nowhere" - }; - match UnixStream::connect(&path) { - Ok(..) => panic!(), - Err(e) => { - assert!(e.kind == FileNotFound || e.kind == OtherIoError); - } - } - } - - #[test] - fn smoke() { - smalltest(move |mut server| { - let mut buf = [0]; - server.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - }, move|mut client| { - client.write(&[99]).unwrap(); - }) - } - - #[cfg_attr(windows, ignore)] // FIXME(#12516) - #[test] - fn read_eof() { - smalltest(move|mut server| { - let mut buf = [0]; - assert!(server.read(&mut buf).is_err()); - assert!(server.read(&mut buf).is_err()); - }, move|_client| { - // drop the client - }) - } - - #[test] - fn write_begone() { - smalltest(move|mut server| { - let buf = [0]; - loop { - match server.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == BrokenPipe || - e.kind == NotConnected || - e.kind == ConnectionReset, - "unknown error {}", e); - break; - } - } - } - }, move|_client| { - // drop the client - }) - } - - #[test] - fn accept_lots() { - let times = 10; - let path1 = next_test_unix(); - let path2 = path1.clone(); - - let mut acceptor = match UnixListener::bind(&path1).listen() { - Ok(a) => a, - Err(e) => panic!("failed listen: {}", e), - }; - - let _t = thread::spawn(move|| { - for _ in 0..times { - let mut stream = UnixStream::connect(&path2); - match stream.write(&[100]) { - Ok(..) => {} - Err(e) => panic!("failed write: {}", e) - } - } - }); - - for _ in 0..times { - let mut client = acceptor.accept(); - let mut buf = [0]; - match client.read(&mut buf) { - Ok(..) => {} - Err(e) => panic!("failed read/accept: {}", e), - } - assert_eq!(buf[0], 100); - } - } - - #[cfg(unix)] - #[test] - fn path_exists() { - let path = next_test_unix(); - let _acceptor = UnixListener::bind(&path).listen(); - assert!(path.exists()); - } - - #[test] - fn unix_clone_smoke() { - let addr = next_test_unix(); - let mut acceptor = UnixListener::bind(&addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = UnixStream::connect(&addr); - let mut buf = [0, 0]; - debug!("client reading"); - assert_eq!(s.read(&mut buf), Ok(1)); - assert_eq!(buf[0], 1); - debug!("client writing"); - s.write(&[2]).unwrap(); - debug!("client dropping"); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - rx1.recv().unwrap(); - debug!("writer writing"); - s2.write(&[1]).unwrap(); - debug!("writer done"); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - debug!("reader reading"); - assert_eq!(s1.read(&mut buf), Ok(1)); - debug!("reader done"); - rx2.recv().unwrap(); - } - - #[test] - fn unix_clone_two_read() { - let addr = next_test_unix(); - let mut acceptor = UnixListener::bind(&addr).listen(); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - let mut s = UnixStream::connect(&addr); - s.write(&[1]).unwrap(); - rx.recv().unwrap(); - s.write(&[2]).unwrap(); - rx.recv().unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - let mut buf = [0, 0]; - s2.read(&mut buf).unwrap(); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - s1.read(&mut buf).unwrap(); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - } - - #[test] - fn unix_clone_two_write() { - let addr = next_test_unix(); - let mut acceptor = UnixListener::bind(&addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = UnixStream::connect(&addr); - let buf = &mut [0, 1]; - s.read(buf).unwrap(); - s.read(buf).unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - s2.write(&[1]).unwrap(); - tx.send(()).unwrap(); - }); - s1.write(&[2]).unwrap(); - - rx.recv().unwrap(); - } - - #[cfg(not(windows))] - #[test] - fn drop_removes_listener_path() { - let path = next_test_unix(); - let l = UnixListener::bind(&path).unwrap(); - assert!(path.exists()); - drop(l); - assert!(!path.exists()); - } - - #[cfg(not(windows))] - #[test] - fn drop_removes_acceptor_path() { - let path = next_test_unix(); - let l = UnixListener::bind(&path).unwrap(); - assert!(path.exists()); - drop(l.listen().unwrap()); - assert!(!path.exists()); - } - - #[test] - fn accept_timeout() { - let addr = next_test_unix(); - let mut a = UnixListener::bind(&addr).unwrap().listen().unwrap(); - - a.set_timeout(Some(10)); - - // Make sure we time out once and future invocations also time out - let err = a.accept().err().unwrap(); - assert_eq!(err.kind, TimedOut); - let err = a.accept().err().unwrap(); - assert_eq!(err.kind, TimedOut); - - // Also make sure that even though the timeout is expired that we will - // continue to receive any pending connections. - let (tx, rx) = channel(); - let addr2 = addr.clone(); - let _t = thread::spawn(move|| { - tx.send(UnixStream::connect(&addr2).unwrap()).unwrap(); - }); - let l = rx.recv().unwrap(); - for i in 0..1001 { - match a.accept() { - Ok(..) => break, - Err(ref e) if e.kind == TimedOut => {} - Err(e) => panic!("error: {}", e), - } - ::thread::yield_now(); - if i == 1000 { panic!("should have a pending connection") } - } - drop(l); - - // Unset the timeout and make sure that this always blocks. - a.set_timeout(None); - let addr2 = addr.clone(); - let _t = thread::spawn(move|| { - drop(UnixStream::connect(&addr2).unwrap()); - }); - a.accept().unwrap(); - } - - #[test] - fn connect_timeout_error() { - let addr = next_test_unix(); - assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_err()); - } - - #[test] - fn connect_timeout_success() { - let addr = next_test_unix(); - let _a = UnixListener::bind(&addr).unwrap().listen().unwrap(); - assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(100)).is_ok()); - } - - #[test] - fn connect_timeout_zero() { - let addr = next_test_unix(); - let _a = UnixListener::bind(&addr).unwrap().listen().unwrap(); - assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(0)).is_err()); - } - - #[test] - fn connect_timeout_negative() { - let addr = next_test_unix(); - let _a = UnixListener::bind(&addr).unwrap().listen().unwrap(); - assert!(UnixStream::connect_timeout(&addr, Duration::milliseconds(-1)).is_err()); - } - - #[test] - fn close_readwrite_smoke() { - let addr = next_test_unix(); - let a = UnixListener::bind(&addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv(); - }); - - let mut b = [0]; - let mut s = UnixStream::connect(&addr).unwrap(); - let mut s2 = s.clone(); - - // closing should prevent reads/writes - s.close_write().unwrap(); - assert!(s.write(&[0]).is_err()); - s.close_read().unwrap(); - assert!(s.read(&mut b).is_err()); - - // closing should affect previous handles - assert!(s2.write(&[0]).is_err()); - assert!(s2.read(&mut b).is_err()); - - // closing should affect new handles - let mut s3 = s.clone(); - assert!(s3.write(&[0]).is_err()); - assert!(s3.read(&mut b).is_err()); - - // make sure these don't die - let _ = s2.close_read(); - let _ = s2.close_write(); - let _ = s3.close_read(); - let _ = s3.close_write(); - } - - #[test] - fn close_read_wakes_up() { - let addr = next_test_unix(); - let a = UnixListener::bind(&addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv(); - }); - - let mut s = UnixStream::connect(&addr).unwrap(); - let s2 = s.clone(); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - assert!(s2.read(&mut [0]).is_err()); - tx.send(()).unwrap(); - }); - // this should wake up the child task - s.close_read().unwrap(); - - // this test will never finish if the child doesn't wake up - rx.recv().unwrap(); - } - - #[test] - fn readwrite_timeouts() { - let addr = next_test_unix(); - let mut a = UnixListener::bind(&addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = UnixStream::connect(&addr).unwrap(); - rx.recv().unwrap(); - assert!(s.write(&[0]).is_ok()); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - - s.set_timeout(Some(20)); - for i in 0..1001 { - match s.write(&[0; 128 * 1024]) { - Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {}, - Err(IoError { kind: TimedOut, .. }) => break, - Err(e) => panic!("{}", e), - } - if i == 1000 { panic!("should have filled up?!"); } - } - - // I'm not sure as to why, but apparently the write on windows always - // succeeds after the previous timeout. Who knows? - if !cfg!(windows) { - assert_eq!(s.write(&[0]).err().unwrap().kind, TimedOut); - } - - tx.send(()).unwrap(); - s.set_timeout(None); - assert_eq!(s.read(&mut [0, 0]), Ok(1)); - } - - #[test] - fn read_timeouts() { - let addr = next_test_unix(); - let mut a = UnixListener::bind(&addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = UnixStream::connect(&addr).unwrap(); - rx.recv().unwrap(); - let mut amt = 0; - while amt < 100 * 128 * 1024 { - match s.read(&mut [0;128 * 1024]) { - Ok(n) => { amt += n; } - Err(e) => panic!("{}", e), - } - } - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_read_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - - tx.send(()).unwrap(); - for _ in 0..100 { - assert!(s.write(&[0;128 * 1024]).is_ok()); - } - } - - #[test] - fn write_timeouts() { - let addr = next_test_unix(); - let mut a = UnixListener::bind(&addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = UnixStream::connect(&addr).unwrap(); - rx.recv().unwrap(); - assert!(s.write(&[0]).is_ok()); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_write_timeout(Some(20)); - for i in 0..1001 { - match s.write(&[0; 128 * 1024]) { - Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {}, - Err(IoError { kind: TimedOut, .. }) => break, - Err(e) => panic!("{}", e), - } - if i == 1000 { panic!("should have filled up?!"); } - } - - tx.send(()).unwrap(); - assert!(s.read(&mut [0]).is_ok()); - } - - #[test] - fn timeout_concurrent_read() { - let addr = next_test_unix(); - let mut a = UnixListener::bind(&addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = UnixStream::connect(&addr).unwrap(); - rx.recv().unwrap(); - assert!(s.write(&[0]).is_ok()); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - let s2 = s.clone(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - assert!(s2.read(&mut [0]).is_ok()); - tx2.send(()).unwrap(); - }); - - s.set_read_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - tx.send(()).unwrap(); - - rx2.recv().unwrap(); - } - - #[cfg(not(windows))] - #[test] - fn clone_accept_smoke() { - let addr = next_test_unix(); - let l = UnixListener::bind(&addr); - let mut a = l.listen().unwrap(); - let mut a2 = a.clone(); - - let addr2 = addr.clone(); - let _t = thread::spawn(move|| { - let _ = UnixStream::connect(&addr2); - }); - let _t = thread::spawn(move|| { - let _ = UnixStream::connect(&addr); - }); - - assert!(a.accept().is_ok()); - drop(a); - assert!(a2.accept().is_ok()); - } - - #[cfg(not(windows))] // FIXME #17553 - #[test] - fn clone_accept_concurrent() { - let addr = next_test_unix(); - let l = UnixListener::bind(&addr); - let a = l.listen().unwrap(); - let a2 = a.clone(); - - let (tx, rx) = channel(); - let tx2 = tx.clone(); - - let _t = thread::spawn(move|| { - let mut a = a; - tx.send(a.accept()).unwrap() - }); - let _t = thread::spawn(move|| { - let mut a = a2; - tx2.send(a.accept()).unwrap() - }); - - let addr2 = addr.clone(); - let _t = thread::spawn(move|| { - let _ = UnixStream::connect(&addr2); - }); - let _t = thread::spawn(move|| { - let _ = UnixStream::connect(&addr); - }); - - assert!(rx.recv().unwrap().is_ok()); - assert!(rx.recv().unwrap().is_ok()); - } - - #[test] - fn close_accept_smoke() { - let addr = next_test_unix(); - let l = UnixListener::bind(&addr); - let mut a = l.listen().unwrap(); - - a.close_accept().unwrap(); - assert_eq!(a.accept().err().unwrap().kind, EndOfFile); - } - - #[test] - fn close_accept_concurrent() { - let addr = next_test_unix(); - let l = UnixListener::bind(&addr); - let a = l.listen().unwrap(); - let mut a2 = a.clone(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut a = a; - tx.send(a.accept()).unwrap(); - }); - a2.close_accept().unwrap(); - - assert_eq!(rx.recv().unwrap().err().unwrap().kind, EndOfFile); - } -} diff --git a/src/libstd/old_io/net/tcp.rs b/src/libstd/old_io/net/tcp.rs deleted file mode 100644 index 7fc460c16e..0000000000 --- a/src/libstd/old_io/net/tcp.rs +++ /dev/null @@ -1,1483 +0,0 @@ -// Copyright 2013-2014 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. - -//! TCP network connections -//! -//! This module contains the ability to open a TCP stream to a socket address, -//! as well as creating a socket server to accept incoming connections. The -//! destination and binding addresses can either be an IPv4 or IPv6 address. -//! -//! A TCP connection implements the `Reader` and `Writer` traits, while the TCP -//! listener (socket server) implements the `Listener` and `Acceptor` traits. - -use clone::Clone; -use old_io::IoResult; -use result::Result::Err; -use old_io::net::ip::{SocketAddr, ToSocketAddr}; -use old_io::{Reader, Writer, Listener, Acceptor}; -use old_io::{standard_error, TimedOut}; -use option::Option; -use option::Option::{None, Some}; -use time::Duration; - -use sys::tcp::TcpStream as TcpStreamImp; -use sys::tcp::TcpListener as TcpListenerImp; -use sys::tcp::TcpAcceptor as TcpAcceptorImp; - -use sys_common; - -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. -/// -/// The socket will be closed when the value is dropped. -/// -/// # Examples -/// -/// ```no_run -/// # #![feature(old_io, io)] -/// use std::old_io::*; -/// -/// { -/// let mut stream = TcpStream::connect("127.0.0.1:34254"); -/// -/// // ignore the Result -/// let _ = stream.write(&[1]); -/// -/// let mut buf = [0]; -/// let _ = stream.read(&mut buf); // ignore here too -/// } // the stream is closed here -/// ``` -pub struct TcpStream { - inner: TcpStreamImp, -} - -impl TcpStream { - fn new(s: TcpStreamImp) -> TcpStream { - TcpStream { inner: s } - } - - /// Open a TCP connection to a remote host. - /// - /// `addr` is an address of the remote host. Anything which implements `ToSocketAddr` - /// trait can be supplied for the address; see this trait documentation for - /// concrete examples. - pub fn connect(addr: A) -> IoResult { - super::with_addresses(addr, |addr| { - TcpStreamImp::connect(addr, None).map(TcpStream::new) - }) - } - - /// Creates a TCP connection to a remote socket address, timing out after - /// the specified duration. - /// - /// This is the same as the `connect` method, except that if the timeout - /// specified elapses before a connection is made an error will be - /// returned. The error's kind will be `TimedOut`. - /// - /// Same as the `connect` method, `addr` argument type can be anything which - /// implements `ToSocketAddr` trait. - /// - /// If a `timeout` with zero or negative duration is specified then - /// the function returns `Err`, with the error kind set to `TimedOut`. - #[unstable(feature = "io", - reason = "the timeout argument may eventually change types")] - pub fn connect_timeout(addr: A, - timeout: Duration) -> IoResult { - if timeout <= Duration::milliseconds(0) { - return Err(standard_error(TimedOut)); - } - - super::with_addresses(addr, |addr| { - TcpStreamImp::connect(addr, Some(timeout.num_milliseconds() as u64)) - .map(TcpStream::new) - }) - } - - /// Returns the socket address of the remote peer of this TCP connection. - pub fn peer_name(&mut self) -> IoResult { - self.inner.peer_name() - } - - /// Returns the socket address of the local half of this TCP connection. - pub fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() - } - - /// Sets the nodelay flag on this connection to the boolean specified - #[unstable(feature = "io")] - pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { - self.inner.set_nodelay(nodelay) - } - - /// Sets the keepalive timeout to the timeout specified. - /// - /// If the value specified is `None`, then the keepalive flag is cleared on - /// this connection. Otherwise, the keepalive timeout will be set to the - /// specified time, in seconds. - #[unstable(feature = "io")] - pub fn set_keepalive(&mut self, delay_in_seconds: Option) -> IoResult<()> { - self.inner.set_keepalive(delay_in_seconds) - } - - /// Closes the reading half of this connection. - /// - /// This method will close the reading portion of this connection, causing - /// all pending and future reads to immediately return with an error. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, std_misc)] - /// # #![allow(unused_must_use)] - /// use std::old_io::*; - /// use std::time::Duration; - /// use std::thread; - /// - /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let stream2 = stream.clone(); - /// - /// let _t = thread::spawn(move|| { - /// // close this stream after one second - /// timer::sleep(Duration::seconds(1)); - /// let mut stream = stream2; - /// stream.close_read(); - /// }); - /// - /// // wait for some data, will get canceled after one second - /// let mut buf = [0]; - /// stream.read(&mut buf); - /// ``` - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { - self.inner.close_read() - } - - /// Closes the writing half of this connection. - /// - /// This method will close the writing portion of this connection, causing - /// all future writes to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { - self.inner.close_write() - } - - /// Sets a timeout, in milliseconds, for blocking operations on this stream. - /// - /// This function will set a timeout for all blocking operations (including - /// reads and writes) on this stream. The timeout specified is a relative - /// time, in milliseconds, into the future after which point operations will - /// time out. This means that the timeout must be reset periodically to keep - /// it from expiring. Specifying a value of `None` will clear the timeout - /// for this stream. - /// - /// The timeout on this stream is local to this stream only. Setting a - /// timeout does not affect any other cloned instances of this stream, nor - /// does the timeout propagated to cloned handles of this stream. Setting - /// this timeout will override any specific read or write timeouts - /// previously set for this stream. - /// - /// For clarification on the semantics of interrupting a read and a write, - /// take a look at `set_read_timeout` and `set_write_timeout`. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.inner.set_timeout(timeout_ms) - } - - /// Sets the timeout for read operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this read time. - /// This will overwrite any previous read timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending read operation, no - /// action is taken. Otherwise, the read operation will be scheduled to - /// promptly return. If a timeout error is returned, then no data was read - /// during the timeout period. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { - self.inner.set_read_timeout(timeout_ms) - } - - /// Sets the timeout for write operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this write time. - /// This will overwrite any previous write timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending write operation, no - /// action is taken. Otherwise, the pending write operation will be - /// scheduled to promptly return. The actual state of the underlying stream - /// is not specified. - /// - /// The write operation may return an error of type `ShortWrite` which - /// indicates that the object is known to have written an exact number of - /// bytes successfully during the timeout period, and the remaining bytes - /// were never written. - /// - /// If the write operation returns `TimedOut`, then it the timeout primitive - /// does not know how many bytes were written as part of the timeout - /// operation. It may be the case that bytes continue to be written in an - /// asynchronous fashion after the call to write returns. - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { - self.inner.set_write_timeout(timeout_ms) - } -} - -impl Clone for TcpStream { - /// Creates a new handle to this TCP stream, allowing for simultaneous reads - /// and writes of this connection. - /// - /// The underlying TCP stream will not be closed until all handles to the - /// stream have been deallocated. All handles will also follow the same - /// stream, but two concurrent reads will not receive the same data. - /// Instead, the first read will receive the first packet received, and the - /// second read will receive the second packet. - fn clone(&self) -> TcpStream { - TcpStream { inner: self.inner.clone() } - } -} - -impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for TcpStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.write(buf) - } -} - -impl sys_common::AsInner for TcpStream { - fn as_inner(&self) -> &TcpStreamImp { - &self.inner - } -} - -/// A structure representing a socket server. This listener is used to create a -/// `TcpAcceptor` which can be used to accept sockets on a local port. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io)] -/// # fn foo() { -/// use std::old_io::*; -/// use std::thread; -/// -/// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); -/// -/// // bind the listener to the specified address -/// let mut acceptor = listener.listen().unwrap(); -/// -/// fn handle_client(mut stream: TcpStream) { -/// // ... -/// # &mut stream; // silence unused mutability/variable warning -/// } -/// // accept connections and process them, spawning a new tasks for each one -/// for stream in acceptor.incoming() { -/// match stream { -/// Err(e) => { /* connection failed */ } -/// Ok(stream) => { -/// thread::spawn(move|| { -/// // connection succeeded -/// handle_client(stream) -/// }); -/// } -/// } -/// } -/// -/// // close the socket server -/// drop(acceptor); -/// # } -/// ``` -pub struct TcpListener { - inner: TcpListenerImp, -} - -impl TcpListener { - /// Creates a new `TcpListener` which will be bound to the specified address. - /// This listener is not ready for accepting connections, `listen` must be called - /// on it before that's possible. - /// - /// Binding with a port number of 0 will request that the OS assigns a port - /// to this listener. The port allocated can be queried via the - /// `socket_name` function. - /// - /// The address type can be any implementer of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn bind(addr: A) -> IoResult { - super::with_addresses(addr, |addr| { - TcpListenerImp::bind(addr).map(|inner| TcpListener { inner: inner }) - }) - } - - /// Returns the local socket address of this listener. - pub fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() - } -} - -impl Listener for TcpListener { - fn listen(self) -> IoResult { - self.inner.listen(128).map(|a| TcpAcceptor { inner: a }) - } -} - -impl sys_common::AsInner for TcpListener { - fn as_inner(&self) -> &TcpListenerImp { - &self.inner - } -} - -/// The accepting half of a TCP socket server. This structure is created through -/// a `TcpListener`'s `listen` method, and this object can be used to accept new -/// `TcpStream` instances. -pub struct TcpAcceptor { - inner: TcpAcceptorImp, -} - -impl TcpAcceptor { - /// Prevents blocking on all future accepts after `ms` milliseconds have - /// elapsed. - /// - /// This function is used to set a deadline after which this acceptor will - /// time out accepting any connections. The argument is the relative - /// distance, in milliseconds, to a point in the future after which all - /// accepts will fail. - /// - /// If the argument specified is `None`, then any previously registered - /// timeout is cleared. - /// - /// A timeout of `0` can be used to "poll" this acceptor to see if it has - /// any pending connections. All pending connections will be accepted, - /// regardless of whether the timeout has expired or not (the accept will - /// not block in this case). - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, io)] - /// use std::old_io::*; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// - /// // After 100ms have passed, all accepts will fail - /// a.set_timeout(Some(100)); - /// - /// match a.accept() { - /// Ok(..) => println!("accepted a socket"), - /// Err(ref e) if e.kind == TimedOut => { println!("timed out!"); } - /// Err(e) => println!("err: {}", e), - /// } - /// - /// // Reset the timeout and try again - /// a.set_timeout(Some(100)); - /// let socket = a.accept(); - /// - /// // Clear the timeout and block indefinitely waiting for a connection - /// a.set_timeout(None); - /// let socket = a.accept(); - /// ``` - #[unstable(feature = "io", - reason = "the type of the argument and name of this function are \ - subject to change")] - pub fn set_timeout(&mut self, ms: Option) { self.inner.set_timeout(ms); } - - /// Closes the accepting capabilities of this acceptor. - /// - /// This function is similar to `TcpStream`'s `close_{read,write}` methods - /// in that it will affect *all* cloned handles of this acceptor's original - /// handle. - /// - /// Once this function succeeds, all future calls to `accept` will return - /// immediately with an error, preventing all future calls to accept. The - /// underlying socket will not be relinquished back to the OS until all - /// acceptors have been deallocated. - /// - /// This is useful for waking up a thread in an accept loop to indicate that - /// it should exit. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, io)] - /// use std::old_io::*; - /// use std::thread; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// let a2 = a.clone(); - /// - /// let _t = thread::spawn(move|| { - /// let mut a2 = a2; - /// for socket in a2.incoming() { - /// match socket { - /// Ok(s) => { /* handle s */ } - /// Err(ref e) if e.kind == EndOfFile => break, // closed - /// Err(e) => panic!("unexpected error: {}", e), - /// } - /// } - /// }); - /// - /// # fn wait_for_sigint() {} - /// // Now that our accept loop is running, wait for the program to be - /// // requested to exit. - /// wait_for_sigint(); - /// - /// // Signal our accept loop to exit - /// assert!(a.close_accept().is_ok()); - /// ``` - #[unstable(feature = "io")] - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.close_accept() - } -} - -impl Acceptor for TcpAcceptor { - type Connection = TcpStream; - fn accept(&mut self) -> IoResult { - self.inner.accept().map(TcpStream::new) - } -} - -impl Clone for TcpAcceptor { - /// Creates a new handle to this TCP acceptor, allowing for simultaneous - /// accepts. - /// - /// The underlying TCP acceptor will not be closed until all handles to the - /// acceptor have been deallocated. Incoming connections will be received on - /// at most once acceptor, the same connection will not be accepted twice. - /// - /// The `close_accept` method will shut down *all* acceptors cloned from the - /// same original acceptor, whereas the `set_timeout` method only affects - /// the selector that it is called on. - /// - /// This function is useful for creating a handle to invoke `close_accept` - /// on to wake up any other task blocked in `accept`. - fn clone(&self) -> TcpAcceptor { - TcpAcceptor { inner: self.inner.clone() } - } -} - -impl sys_common::AsInner for TcpAcceptor { - fn as_inner(&self) -> &TcpAcceptorImp { - &self.inner - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use sync::mpsc::channel; - use thread; - use old_io::net::tcp::*; - use old_io::net::ip::*; - use old_io::test::*; - use old_io::{EndOfFile, TimedOut, ShortWrite, IoError}; - use old_io::{ConnectionRefused, BrokenPipe, ConnectionAborted}; - use old_io::{ConnectionReset, NotConnected, PermissionDenied, OtherIoError}; - use old_io::{InvalidInput}; - use old_io::{Acceptor, Listener}; - use old_io::{Reader, Writer}; - - // FIXME #11530 this fails on android because tests are run as root - #[cfg_attr(any(windows, target_os = "android"), ignore)] - #[test] - fn bind_error() { - match TcpListener::bind("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, PermissionDenied), - } - } - - #[test] - fn connect_error() { - match TcpStream::connect("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert!((e.kind == ConnectionRefused) - || (e.kind == InvalidInput)), - } - } - - #[test] - fn listen_ip4_localhost() { - let socket_addr = next_test_ip4(); - let listener = TcpListener::bind(socket_addr); - let mut acceptor = listener.listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("localhost", socket_addr.port)); - stream.write(&[144]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 144); - } - - #[test] - fn connect_localhost() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("localhost", addr.port)); - stream.write(&[64]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 64); - } - - #[test] - fn connect_ip4_loopback() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("127.0.0.1", addr.port)); - stream.write(&[44]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 44); - } - - #[test] - fn connect_ip6_loopback() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(("::1", addr.port)); - stream.write(&[66]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 66); - } - - #[test] - fn smoke_test_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - } - - #[test] - fn smoke_test_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - } - - #[test] - fn read_eof_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - } - - #[test] - fn read_eof_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - } - - #[test] - fn read_eof_twice_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - - match stream.read(&mut buf) { - Ok(..) => panic!(), - Err(ref e) => { - assert!(e.kind == NotConnected || e.kind == EndOfFile, - "unknown kind: {:?}", e.kind); - } - } - } - - #[test] - fn read_eof_twice_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let _stream = TcpStream::connect(addr); - // Close - }); - - let mut stream = acceptor.accept(); - let mut buf = [0]; - let nread = stream.read(&mut buf); - assert!(nread.is_err()); - - match stream.read(&mut buf) { - Ok(..) => panic!(), - Err(ref e) => { - assert!(e.kind == NotConnected || e.kind == EndOfFile, - "unknown kind: {:?}", e.kind); - } - } - } - - #[test] - fn write_close_ip4() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr)); - tx.send(()).unwrap(); - }); - - let mut stream = acceptor.accept(); - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - } - } - } - - #[test] - fn write_close_ip6() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr)); - tx.send(()).unwrap(); - }); - - let mut stream = acceptor.accept(); - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!(e.kind == ConnectionReset || - e.kind == BrokenPipe || - e.kind == ConnectionAborted, - "unknown error: {}", e); - } - } - } - - #[test] - fn multiple_connect_serial_ip4() { - let addr = next_test_ip4(); - let max = 10; - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - for _ in 0..max { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - } - }); - - for ref mut stream in acceptor.incoming().take(max) { - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert_eq!(buf[0], 99); - } - } - - #[test] - fn multiple_connect_serial_ip6() { - let addr = next_test_ip6(); - let max = 10; - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - for _ in 0..max { - let mut stream = TcpStream::connect(addr); - stream.write(&[99]).unwrap(); - } - }); - - for ref mut stream in acceptor.incoming().take(max) { - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert_eq!(buf[0], 99); - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule_ip4() { - let addr = next_test_ip4(); - static MAX: isize = 10; - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == i as u8); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[i as u8]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule_ip6() { - let addr = next_test_ip6(); - static MAX: isize = 10; - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == i as u8); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[i as u8]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule_ip4() { - static MAX: isize = 10; - let addr = next_test_ip4(); - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for stream in acceptor.incoming().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[99]).unwrap(); - }); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule_ip6() { - static MAX: isize = 10; - let addr = next_test_ip6(); - let acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - for stream in acceptor.incoming().take(MAX as usize) { - // Start another task to handle the connection - let _t = thread::spawn(move|| { - let mut stream = stream; - let mut buf = [0]; - stream.read(&mut buf).unwrap(); - assert!(buf[0] == 99); - debug!("read"); - }); - } - }); - - connect(0, addr); - - fn connect(i: isize, addr: SocketAddr) { - if i == MAX { return } - - let _t = thread::spawn(move|| { - debug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - debug!("writing"); - stream.write(&[99]).unwrap(); - }); - } - } - - pub fn socket_name(addr: SocketAddr) { - let mut listener = TcpListener::bind(addr).unwrap(); - - // Make sure socket_name gives - // us the socket we binded to. - let so_name = listener.socket_name(); - assert!(so_name.is_ok()); - assert_eq!(addr, so_name.unwrap()); - } - - pub fn peer_name(addr: SocketAddr) { - let acceptor = TcpListener::bind(addr).listen(); - let _t = thread::spawn(move|| { - let mut acceptor = acceptor; - acceptor.accept().unwrap(); - }); - - let stream = TcpStream::connect(addr); - - assert!(stream.is_ok()); - let mut stream = stream.unwrap(); - - // Make sure peer_name gives us the - // address/port of the peer we've - // connected to. - let peer_name = stream.peer_name(); - assert!(peer_name.is_ok()); - assert_eq!(addr, peer_name.unwrap()); - } - - #[test] - fn socket_and_peer_name_ip4() { - peer_name(next_test_ip4()); - socket_name(next_test_ip4()); - } - - #[test] - fn socket_and_peer_name_ip6() { - // FIXME: peer name is not consistent - //peer_name(next_test_ip6()); - socket_name(next_test_ip6()); - } - - #[test] - fn partial_read() { - let addr = next_test_ip4(); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut srv = TcpListener::bind(addr).listen().unwrap(); - tx.send(()).unwrap(); - let mut cl = srv.accept().unwrap(); - cl.write(&[10]).unwrap(); - let mut b = [0]; - cl.read(&mut b).unwrap(); - tx.send(()).unwrap(); - }); - - rx.recv().unwrap(); - let mut c = TcpStream::connect(addr).unwrap(); - let mut b = [0; 10]; - assert_eq!(c.read(&mut b), Ok(1)); - c.write(&[1]).unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn double_bind() { - let addr = next_test_ip4(); - let listener = TcpListener::bind(addr).unwrap().listen(); - assert!(listener.is_ok()); - match TcpListener::bind(addr).listen() { - Ok(..) => panic!(), - Err(e) => { - assert!(e.kind == ConnectionRefused || e.kind == OtherIoError, - "unknown error: {} {:?}", e, e.kind); - } - } - } - - #[test] - fn fast_rebind() { - let addr = next_test_ip4(); - let (tx, rx) = channel(); - - let _t = thread::spawn(move|| { - rx.recv().unwrap(); - let _stream = TcpStream::connect(addr).unwrap(); - // Close - rx.recv().unwrap(); - }); - - { - let mut acceptor = TcpListener::bind(addr).listen(); - tx.send(()).unwrap(); - { - let _stream = acceptor.accept().unwrap(); - // Close client - tx.send(()).unwrap(); - } - // Close listener - } - let _listener = TcpListener::bind(addr); - } - - #[test] - fn tcp_clone_smoke() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::connect(addr); - let mut buf = [0, 0]; - assert_eq!(s.read(&mut buf), Ok(1)); - assert_eq!(buf[0], 1); - s.write(&[2]).unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - rx1.recv().unwrap(); - s2.write(&[1]).unwrap(); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(s1.read(&mut buf), Ok(1)); - rx2.recv().unwrap(); - } - - #[test] - fn tcp_clone_two_read() { - let addr = next_test_ip6(); - let mut acceptor = TcpListener::bind(addr).listen(); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::connect(addr); - s.write(&[1]).unwrap(); - rx.recv().unwrap(); - s.write(&[2]).unwrap(); - rx.recv().unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - let mut buf = [0, 0]; - s2.read(&mut buf).unwrap(); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - s1.read(&mut buf).unwrap(); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - } - - #[test] - fn tcp_clone_two_write() { - let addr = next_test_ip4(); - let mut acceptor = TcpListener::bind(addr).listen(); - - let _t = thread::spawn(move|| { - let mut s = TcpStream::connect(addr); - let mut buf = [0, 1]; - s.read(&mut buf).unwrap(); - s.read(&mut buf).unwrap(); - }); - - let mut s1 = acceptor.accept().unwrap(); - let s2 = s1.clone(); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - s2.write(&[1]).unwrap(); - done.send(()).unwrap(); - }); - s1.write(&[2]).unwrap(); - - rx.recv().unwrap(); - } - - #[test] - fn shutdown_smoke() { - let addr = next_test_ip4(); - let a = TcpListener::bind(addr).unwrap().listen(); - let _t = thread::spawn(move|| { - let mut a = a; - let mut c = a.accept().unwrap(); - assert_eq!(c.read_to_end(), Ok(vec!())); - c.write(&[1]).unwrap(); - }); - - let mut s = TcpStream::connect(addr).unwrap(); - assert!(s.inner.close_write().is_ok()); - assert!(s.write(&[1]).is_err()); - assert_eq!(s.read_to_end(), Ok(vec!(1))); - } - - #[test] - fn accept_timeout() { - let addr = next_test_ip4(); - let mut a = TcpListener::bind(addr).unwrap().listen().unwrap(); - - a.set_timeout(Some(10)); - - // Make sure we time out once and future invocations also time out - let err = a.accept().err().unwrap(); - assert_eq!(err.kind, TimedOut); - let err = a.accept().err().unwrap(); - assert_eq!(err.kind, TimedOut); - - // Also make sure that even though the timeout is expired that we will - // continue to receive any pending connections. - // - // FIXME: freebsd apparently never sees the pending connection, but - // testing manually always works. Need to investigate this - // flakiness. - if !cfg!(target_os = "freebsd") { - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - tx.send(TcpStream::connect(addr).unwrap()).unwrap(); - }); - let _l = rx.recv().unwrap(); - for i in 0..1001 { - match a.accept() { - Ok(..) => break, - Err(ref e) if e.kind == TimedOut => {} - Err(e) => panic!("error: {}", e), - } - ::thread::yield_now(); - if i == 1000 { panic!("should have a pending connection") } - } - } - - // Unset the timeout and make sure that this always blocks. - a.set_timeout(None); - let _t = thread::spawn(move|| { - drop(TcpStream::connect(addr).unwrap()); - }); - a.accept().unwrap(); - } - - #[test] - fn close_readwrite_smoke() { - let addr = next_test_ip4(); - let a = TcpListener::bind(addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv().unwrap(); - }); - - let mut b = [0]; - let mut s = TcpStream::connect(addr).unwrap(); - let mut s2 = s.clone(); - - // closing should prevent reads/writes - s.close_write().unwrap(); - assert!(s.write(&[0]).is_err()); - s.close_read().unwrap(); - assert!(s.read(&mut b).is_err()); - - // closing should affect previous handles - assert!(s2.write(&[0]).is_err()); - assert!(s2.read(&mut b).is_err()); - - // closing should affect new handles - let mut s3 = s.clone(); - assert!(s3.write(&[0]).is_err()); - assert!(s3.read(&mut b).is_err()); - - // make sure these don't die - let _ = s2.close_read(); - let _ = s2.close_write(); - let _ = s3.close_read(); - let _ = s3.close_write(); - } - - #[test] - fn close_read_wakes_up() { - let addr = next_test_ip4(); - let a = TcpListener::bind(addr).listen().unwrap(); - let (_tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut a = a; - let _s = a.accept().unwrap(); - let _ = rx.recv().unwrap(); - }); - - let mut s = TcpStream::connect(addr).unwrap(); - let s2 = s.clone(); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - assert!(s2.read(&mut [0]).is_err()); - tx.send(()).unwrap(); - }); - // this should wake up the child task - s.close_read().unwrap(); - - // this test will never finish if the child doesn't wake up - rx.recv().unwrap(); - } - - #[test] - fn readwrite_timeouts() { - let addr = next_test_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - assert!(s.write(&[0]).is_ok()); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - - s.set_timeout(Some(20)); - for i in 0..1001 { - match s.write(&[0; 128 * 1024]) { - Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {}, - Err(IoError { kind: TimedOut, .. }) => break, - Err(e) => panic!("{}", e), - } - if i == 1000 { panic!("should have filled up?!"); } - } - assert_eq!(s.write(&[0]).err().unwrap().kind, TimedOut); - - tx.send(()).unwrap(); - s.set_timeout(None); - assert_eq!(s.read(&mut [0, 0]), Ok(1)); - } - - #[test] - fn read_timeouts() { - let addr = next_test_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - let mut amt = 0; - while amt < 100 * 128 * 1024 { - match s.read(&mut [0;128 * 1024]) { - Ok(n) => { amt += n; } - Err(e) => panic!("{}", e), - } - } - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_read_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - - tx.send(()).unwrap(); - for _ in 0..100 { - assert!(s.write(&[0;128 * 1024]).is_ok()); - } - } - - #[test] - fn write_timeouts() { - let addr = next_test_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - assert!(s.write(&[0]).is_ok()); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - s.set_write_timeout(Some(20)); - for i in 0..1001 { - match s.write(&[0; 128 * 1024]) { - Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {}, - Err(IoError { kind: TimedOut, .. }) => break, - Err(e) => panic!("{}", e), - } - if i == 1000 { panic!("should have filled up?!"); } - } - assert_eq!(s.write(&[0]).err().unwrap().kind, TimedOut); - - tx.send(()).unwrap(); - assert!(s.read(&mut [0]).is_ok()); - } - - #[test] - fn timeout_concurrent_read() { - let addr = next_test_ip6(); - let mut a = TcpListener::bind(addr).listen().unwrap(); - let (tx, rx) = channel::<()>(); - thread::spawn(move|| { - let mut s = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - assert_eq!(s.write(&[0]), Ok(())); - let _ = rx.recv(); - }); - - let mut s = a.accept().unwrap(); - let s2 = s.clone(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut s2 = s2; - assert_eq!(s2.read(&mut [0]), Ok(1)); - tx2.send(()).unwrap(); - }); - - s.set_read_timeout(Some(20)); - assert_eq!(s.read(&mut [0]).err().unwrap().kind, TimedOut); - tx.send(()).unwrap(); - - rx2.recv().unwrap(); - } - - #[test] - fn clone_while_reading() { - let addr = next_test_ip6(); - let listen = TcpListener::bind(addr); - let mut accept = listen.listen().unwrap(); - - // Enqueue a task to write to a socket - let (tx, rx) = channel(); - let (txdone, rxdone) = channel(); - let txdone2 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp = TcpStream::connect(addr).unwrap(); - rx.recv().unwrap(); - tcp.write_u8(0).unwrap(); - txdone2.send(()).unwrap(); - }); - - // Spawn off a reading clone - let tcp = accept.accept().unwrap(); - let tcp2 = tcp.clone(); - let txdone3 = txdone.clone(); - let _t = thread::spawn(move|| { - let mut tcp2 = tcp2; - tcp2.read_u8().unwrap(); - txdone3.send(()).unwrap(); - }); - - // Try to ensure that the reading clone is indeed reading - for _ in 0..50 { - ::thread::yield_now(); - } - - // clone the handle again while it's reading, then let it finish the - // read. - let _ = tcp.clone(); - tx.send(()).unwrap(); - rxdone.recv().unwrap(); - rxdone.recv().unwrap(); - } - - #[test] - fn clone_accept_smoke() { - let addr = next_test_ip4(); - let l = TcpListener::bind(addr); - let mut a = l.listen().unwrap(); - let mut a2 = a.clone(); - - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - - assert!(a.accept().is_ok()); - assert!(a2.accept().is_ok()); - } - - #[test] - fn clone_accept_concurrent() { - let addr = next_test_ip4(); - let l = TcpListener::bind(addr); - let a = l.listen().unwrap(); - let a2 = a.clone(); - - let (tx, rx) = channel(); - let tx2 = tx.clone(); - - let _t = thread::spawn(move|| { - let mut a = a; - tx.send(a.accept()).unwrap(); - }); - let _t = thread::spawn(move|| { - let mut a = a2; - tx2.send(a.accept()).unwrap(); - }); - - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - let _t = thread::spawn(move|| { - let _ = TcpStream::connect(addr); - }); - - assert!(rx.recv().unwrap().is_ok()); - assert!(rx.recv().unwrap().is_ok()); - } - - #[test] - fn close_accept_smoke() { - let addr = next_test_ip4(); - let l = TcpListener::bind(addr); - let mut a = l.listen().unwrap(); - - a.close_accept().unwrap(); - assert_eq!(a.accept().err().unwrap().kind, EndOfFile); - } - - #[test] - fn close_accept_concurrent() { - let addr = next_test_ip4(); - let l = TcpListener::bind(addr); - let a = l.listen().unwrap(); - let mut a2 = a.clone(); - - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut a = a; - tx.send(a.accept()).unwrap(); - }); - a2.close_accept().unwrap(); - - assert_eq!(rx.recv().unwrap().err().unwrap().kind, EndOfFile); - } -} diff --git a/src/libstd/old_io/net/udp.rs b/src/libstd/old_io/net/udp.rs deleted file mode 100644 index 196447d71e..0000000000 --- a/src/libstd/old_io/net/udp.rs +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright 2013 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. - -//! UDP (User Datagram Protocol) network connections. -//! -//! This module contains the ability to open a UDP stream to a socket address. -//! The destination and binding addresses can either be an IPv4 or IPv6 -//! address. There is no corresponding notion of a server because UDP is a -//! datagram protocol. - -use clone::Clone; -use old_io::net::ip::{SocketAddr, IpAddr, ToSocketAddr}; -use old_io::IoResult; -use option::Option; -use sys::udp::UdpSocket as UdpSocketImp; -use sys_common; - -/// A User Datagram Protocol socket. -/// -/// This is an implementation of a bound UDP socket. This supports both IPv4 and -/// IPv6 addresses, and there is no corresponding notion of a server because UDP -/// is a datagram protocol. -/// -/// # Examples -/// -/// ```rust,no_run -/// # #![feature(old_io)] -/// # #![allow(unused_must_use)] -/// -/// use std::old_io::net::udp::UdpSocket; -/// use std::old_io::net::ip::{Ipv4Addr, SocketAddr}; -/// fn main() { -/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 34254 }; -/// let mut socket = match UdpSocket::bind(addr) { -/// Ok(s) => s, -/// Err(e) => panic!("couldn't bind socket: {}", e), -/// }; -/// -/// let mut buf = [0; 10]; -/// match socket.recv_from(&mut buf) { -/// Ok((amt, src)) => { -/// // Send a reply to the socket we received data from -/// let buf = &mut buf[..amt]; -/// buf.reverse(); -/// socket.send_to(buf, src); -/// } -/// Err(e) => println!("couldn't receive a datagram: {}", e) -/// } -/// drop(socket); // close the socket -/// } -/// ``` -pub struct UdpSocket { - inner: UdpSocketImp, -} - -impl UdpSocket { - /// Creates a UDP socket from the given address. - /// - /// Address type can be any implementor of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn bind(addr: A) -> IoResult { - super::with_addresses(addr, |addr| { - UdpSocketImp::bind(addr).map(|s| UdpSocket { inner: s }) - }) - } - - /// Receives data from the socket. On success, returns the number of bytes - /// read and the address from whence the data came. - pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(usize, SocketAddr)> { - self.inner.recv_from(buf) - } - - /// Sends data on the socket to the given address. Returns nothing on - /// success. - /// - /// Address type can be any implementer of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn send_to(&mut self, buf: &[u8], addr: A) -> IoResult<()> { - super::with_addresses(addr, |addr| self.inner.send_to(buf, addr)) - } - - /// Returns the socket address that this socket was created from. - pub fn socket_name(&mut self) -> IoResult { - self.inner.socket_name() - } - - /// Joins a multicast IP address (becomes a member of it) - #[unstable(feature = "io")] - pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - self.inner.join_multicast(multi) - } - - /// Leaves a multicast IP address (drops membership from it) - #[unstable(feature = "io")] - pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - self.inner.leave_multicast(multi) - } - - /// Set the multicast loop flag to the specified value - /// - /// This lets multicast packets loop back to local sockets (if enabled) - #[unstable(feature = "io")] - pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { - self.inner.set_multicast_loop(on) - } - - /// Sets the multicast TTL - #[unstable(feature = "io")] - pub fn set_multicast_ttl(&mut self, ttl: isize) -> IoResult<()> { - self.inner.multicast_time_to_live(ttl) - } - - /// Sets this socket's TTL - #[unstable(feature = "io")] - pub fn set_ttl(&mut self, ttl: isize) -> IoResult<()> { - self.inner.time_to_live(ttl) - } - - /// Sets the broadcast flag on or off - #[unstable(feature = "io")] - pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> { - self.inner.set_broadcast(broadcast) - } - - /// Sets the read/write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.inner.set_timeout(timeout_ms) - } - - /// Sets the read timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { - self.inner.set_read_timeout(timeout_ms) - } - - /// Sets the write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[unstable(feature = "io", - reason = "the timeout argument may change in type and value")] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { - self.inner.set_write_timeout(timeout_ms) - } -} - -impl Clone for UdpSocket { - /// Creates a new handle to this UDP socket, allowing for simultaneous - /// reads and writes of the socket. - /// - /// The underlying UDP socket will not be closed until all handles to the - /// socket have been deallocated. Two concurrent reads will not receive - /// the same data. Instead, the first read will receive the first packet - /// received, and the second read will receive the second packet. - fn clone(&self) -> UdpSocket { - UdpSocket { - inner: self.inner.clone(), - } - } -} - -impl sys_common::AsInner for UdpSocket { - fn as_inner(&self) -> &UdpSocketImp { - &self.inner - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use sync::mpsc::channel; - use old_io::net::ip::*; - use old_io::test::*; - use old_io::{IoError, TimedOut, PermissionDenied, ShortWrite}; - use super::*; - use thread; - - // FIXME #11530 this fails on android because tests are run as root - #[cfg_attr(any(windows, target_os = "android"), ignore)] - #[test] - fn bind_error() { - let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 }; - match UdpSocket::bind(addr) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, PermissionDenied), - } - } - - #[test] - fn socket_smoke_test_ip4() { - let server_ip = next_test_ip4(); - let client_ip = next_test_ip4(); - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - - let _t = thread::spawn(move|| { - match UdpSocket::bind(client_ip) { - Ok(ref mut client) => { - rx1.recv().unwrap(); - client.send_to(&[99], server_ip).unwrap() - } - Err(..) => panic!() - } - tx2.send(()).unwrap(); - }); - - match UdpSocket::bind(server_ip) { - Ok(ref mut server) => { - tx1.send(()).unwrap(); - let mut buf = [0]; - match server.recv_from(&mut buf) { - Ok((nread, src)) => { - assert_eq!(nread, 1); - assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); - } - Err(..) => panic!() - } - } - Err(..) => panic!() - } - rx2.recv().unwrap(); - } - - #[test] - fn socket_smoke_test_ip6() { - let server_ip = next_test_ip6(); - let client_ip = next_test_ip6(); - let (tx, rx) = channel::<()>(); - - let _t = thread::spawn(move|| { - match UdpSocket::bind(client_ip) { - Ok(ref mut client) => { - rx.recv().unwrap(); - client.send_to(&[99], server_ip).unwrap() - } - Err(..) => panic!() - } - }); - - match UdpSocket::bind(server_ip) { - Ok(ref mut server) => { - tx.send(()).unwrap(); - let mut buf = [0]; - match server.recv_from(&mut buf) { - Ok((nread, src)) => { - assert_eq!(nread, 1); - assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); - } - Err(..) => panic!() - } - } - Err(..) => panic!() - } - } - - pub fn socket_name(addr: SocketAddr) { - let server = UdpSocket::bind(addr); - - assert!(server.is_ok()); - let mut server = server.unwrap(); - - // Make sure socket_name gives - // us the socket we binded to. - let so_name = server.socket_name(); - assert!(so_name.is_ok()); - assert_eq!(addr, so_name.unwrap()); - } - - #[test] - fn socket_name_ip4() { - socket_name(next_test_ip4()); - } - - #[test] - fn socket_name_ip6() { - socket_name(next_test_ip6()); - } - - #[test] - fn udp_clone_smoke() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); - let mut sock1 = UdpSocket::bind(addr1).unwrap(); - let sock2 = UdpSocket::bind(addr2).unwrap(); - - let _t = thread::spawn(move|| { - let mut sock2 = sock2; - let mut buf = [0, 0]; - assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1))); - assert_eq!(buf[0], 1); - sock2.send_to(&[2], addr1).unwrap(); - }); - - let sock3 = sock1.clone(); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut sock3 = sock3; - rx1.recv().unwrap(); - sock3.send_to(&[1], addr2).unwrap(); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2))); - rx2.recv().unwrap(); - } - - #[test] - fn udp_clone_two_read() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); - let mut sock1 = UdpSocket::bind(addr1).unwrap(); - let sock2 = UdpSocket::bind(addr2).unwrap(); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move|| { - let mut sock2 = sock2; - sock2.send_to(&[1], addr1).unwrap(); - rx.recv().unwrap(); - sock2.send_to(&[2], addr1).unwrap(); - rx.recv().unwrap(); - }); - - let sock3 = sock1.clone(); - - let (done, rx) = channel(); - let _t = thread::spawn(move|| { - let mut sock3 = sock3; - let mut buf = [0, 0]; - sock3.recv_from(&mut buf).unwrap(); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - sock1.recv_from(&mut buf).unwrap(); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - } - - #[test] - fn udp_clone_two_write() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); - let mut sock1 = UdpSocket::bind(addr1).unwrap(); - let sock2 = UdpSocket::bind(addr2).unwrap(); - - let (tx, rx) = channel(); - let (serv_tx, serv_rx) = channel(); - - let _t = thread::spawn(move|| { - let mut sock2 = sock2; - let mut buf = [0, 1]; - - rx.recv().unwrap(); - match sock2.recv_from(&mut buf) { - Ok(..) => {} - Err(e) => panic!("failed receive: {}", e), - } - serv_tx.send(()).unwrap(); - }); - - let sock3 = sock1.clone(); - - let (done, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - let mut sock3 = sock3; - match sock3.send_to(&[1], addr2) { - Ok(..) => { let _ = tx2.send(()); } - Err(..) => {} - } - done.send(()).unwrap(); - }); - match sock1.send_to(&[2], addr2) { - Ok(..) => { let _ = tx.send(()); } - Err(..) => {} - } - drop(tx); - - rx.recv().unwrap(); - serv_rx.recv().unwrap(); - } - - #[cfg(not(windows))] // FIXME #17553 - #[test] - fn recv_from_timeout() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); - let mut a = UdpSocket::bind(addr1).unwrap(); - let a2 = UdpSocket::bind(addr2).unwrap(); - - let (tx, rx) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - let mut a = a2; - assert_eq!(a.recv_from(&mut [0]), Ok((1, addr1))); - assert_eq!(a.send_to(&[0], addr1), Ok(())); - rx.recv().unwrap(); - assert_eq!(a.send_to(&[0], addr1), Ok(())); - - tx2.send(()).unwrap(); - }); - - // Make sure that reads time out, but writes can continue - a.set_read_timeout(Some(20)); - assert_eq!(a.recv_from(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(a.recv_from(&mut [0]).err().unwrap().kind, TimedOut); - assert_eq!(a.send_to(&[0], addr2), Ok(())); - - // Cloned handles should be able to block - let mut a2 = a.clone(); - assert_eq!(a2.recv_from(&mut [0]), Ok((1, addr2))); - - // Clearing the timeout should allow for receiving - a.set_timeout(None); - tx.send(()).unwrap(); - assert_eq!(a2.recv_from(&mut [0]), Ok((1, addr2))); - - // Make sure the child didn't die - rx2.recv().unwrap(); - } - - #[test] - fn send_to_timeout() { - let addr1 = next_test_ip4(); - let addr2 = next_test_ip4(); - let mut a = UdpSocket::bind(addr1).unwrap(); - let _b = UdpSocket::bind(addr2).unwrap(); - - a.set_write_timeout(Some(1000)); - for _ in 0..100 { - match a.send_to(&[0;4*1024], addr2) { - Ok(()) | Err(IoError { kind: ShortWrite(..), .. }) => {}, - Err(IoError { kind: TimedOut, .. }) => break, - Err(e) => panic!("other error: {}", e), - } - } - } -} diff --git a/src/libstd/old_io/pipe.rs b/src/libstd/old_io/pipe.rs deleted file mode 100644 index fd1df49473..0000000000 --- a/src/libstd/old_io/pipe.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2013 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. - -//! Synchronous, in-memory pipes. -//! -//! Currently these aren't particularly useful, there only exists bindings -//! enough so that pipes can be created to child processes. - -#![allow(missing_docs)] - -use prelude::v1::*; - -use old_io::{IoResult, Reader, Writer}; -use libc; -use sync::Arc; - -use sys_common; -use sys; -use sys::fs::FileDesc as FileDesc; - -/// A synchronous, in-memory pipe. -pub struct PipeStream { - inner: Arc -} - -pub struct PipePair { - pub reader: PipeStream, - pub writer: PipeStream, -} - -impl PipeStream { - /// Consumes a file descriptor to return a pipe stream that will have - /// synchronous, but non-blocking reads/writes. This is useful if the file - /// descriptor is acquired via means other than the standard methods. - /// - /// This operation consumes ownership of the file descriptor and it will be - /// closed once the object is deallocated. - /// - /// # Examples - /// - /// ```{rust,no_run} - /// # #![feature(old_io, libc, io)] - /// # #![allow(unused_must_use)] - /// extern crate libc; - /// - /// use std::old_io::*; - /// - /// fn main() { - /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); - /// pipe.write(b"Hello, stderr!"); - /// } - /// ``` - pub fn open(fd: libc::c_int) -> IoResult { - Ok(PipeStream::from_filedesc(FileDesc::new(fd, true))) - } - - // FIXME: expose this some other way - /// Wrap a FileDesc directly, taking ownership. - #[doc(hidden)] - pub fn from_filedesc(fd: FileDesc) -> PipeStream { - PipeStream { inner: Arc::new(fd) } - } - - /// Creates a pair of in-memory OS pipes for a unidirectional communication - /// stream. - /// - /// The structure returned contains a reader and writer I/O object. Data - /// written to the writer can be read from the reader. - /// - /// # Errors - /// - /// This function can fail to succeed if the underlying OS has run out of - /// available resources to allocate a new pipe. - pub fn pair() -> IoResult { - let (reader, writer) = try!(unsafe { sys::os::pipe() }); - Ok(PipePair { - reader: PipeStream::from_filedesc(reader), - writer: PipeStream::from_filedesc(writer), - }) - } -} - -impl sys_common::AsInner for PipeStream { - fn as_inner(&self) -> &sys::fs::FileDesc { - &*self.inner - } -} - -impl Clone for PipeStream { - fn clone(&self) -> PipeStream { - PipeStream { inner: self.inner.clone() } - } -} - -impl Reader for PipeStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.read(buf) - } -} - -impl Writer for PipeStream { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner.write(buf) - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use old_io::{Writer, Reader}; - use sync::mpsc::channel; - use thread; - - #[test] - fn partial_read() { - use os; - use old_io::pipe::PipeStream; - - let (reader, writer) = unsafe { ::sys::os::pipe().unwrap() }; - let out = PipeStream::open(writer.unwrap()); - let mut input = PipeStream::open(reader.unwrap()); - let (tx, rx) = channel(); - let _t = thread::spawn(move|| { - let mut out = out; - out.write(&[10]).unwrap(); - rx.recv().unwrap(); // don't close the pipe until the other read has finished - }); - - let mut buf = [0; 10]; - input.read(&mut buf).unwrap(); - tx.send(()).unwrap(); - } -} diff --git a/src/libstd/old_io/process.rs b/src/libstd/old_io/process.rs deleted file mode 100644 index ad2d5b4681..0000000000 --- a/src/libstd/old_io/process.rs +++ /dev/null @@ -1,1239 +0,0 @@ -// Copyright 2013 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. - -//! Bindings for executing child processes - -#![allow(non_upper_case_globals)] -#![unstable(feature = "old_io")] -#![deprecated(since = "1.0.0", - reason = "replaced with the std::process module")] - -pub use self::StdioContainer::*; -pub use self::ProcessExit::*; - -use prelude::v1::*; - -use collections::HashMap; -use ffi::CString; -use fmt; -use old_io::pipe::{PipeStream, PipePair}; -use old_io::{IoResult, IoError, Reader, Writer}; -use old_io; -use old_path::{Path, GenericPath}; -use libc; -use os; -use old_path::BytesContainer; -use sync::mpsc::{channel, Receiver}; -use sys::fs::FileDesc; -use sys::process::Process as ProcessImp; -use sys; -use thread; - -#[cfg(windows)] use hash; -#[cfg(windows)] use str; - -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(windows)] pub const PleaseExitSignal: isize = 15; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(windows)] pub const MustDieSignal: isize = 9; -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(not(windows))] pub const PleaseExitSignal: isize = libc::SIGTERM as isize; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(not(windows))] pub const MustDieSignal: isize = libc::SIGKILL as isize; - -/// Representation of a running or exited child process. -/// -/// This structure is used to represent and manage child processes. A child -/// process is created via the `Command` struct, which configures the spawning -/// process and can itself be constructed using a builder-style interface. -/// -/// # Examples -/// -/// ```should_panic -/// # #![feature(old_io)] -/// use std::old_io::*; -/// -/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() { -/// Ok(child) => child, -/// Err(e) => panic!("failed to execute child: {}", e), -/// }; -/// -/// let contents = child.stdout.as_mut().unwrap().read_to_end(); -/// assert!(child.wait().unwrap().success()); -/// ``` -pub struct Process { - handle: ProcessImp, - forget: bool, - - /// None until wait() is called. - exit_code: Option, - - /// Manually delivered signal - exit_signal: Option, - - /// Deadline after which wait() will return - deadline: u64, - - /// Handle to the child's stdin, if the `stdin` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdin: Option, - - /// Handle to the child's stdout, if the `stdout` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdout: Option, - - /// Handle to the child's stderr, if the `stderr` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stderr: Option, -} - -/// A representation of environment variable name -/// It compares case-insensitive on Windows and case-sensitive everywhere else. -#[cfg(not(windows))] -#[derive(Hash, PartialEq, Eq, Clone, Debug)] -struct EnvKey(CString); - -#[doc(hidden)] -#[cfg(windows)] -#[derive(Eq, Clone, Debug)] -struct EnvKey(CString); - -#[cfg(windows)] -impl hash::Hash for EnvKey { - fn hash(&self, state: &mut H) { - use ascii::AsciiExt; - let &EnvKey(ref x) = self; - match str::from_utf8(x.as_bytes()) { - Ok(s) => for ch in s.chars() { - ch.to_ascii_lowercase().hash(state); - }, - Err(..) => x.hash(state) - } - } -} - -#[cfg(windows)] -impl PartialEq for EnvKey { - fn eq(&self, other: &EnvKey) -> bool { - use ascii::AsciiExt; - let &EnvKey(ref x) = self; - let &EnvKey(ref y) = other; - match (str::from_utf8(x.as_bytes()), str::from_utf8(y.as_bytes())) { - (Ok(xs), Ok(ys)) => { - if xs.len() != ys.len() { - return false - } else { - for (xch, ych) in xs.chars().zip(ys.chars()) { - if xch.to_ascii_lowercase() != ych.to_ascii_lowercase() { - return false; - } - } - return true; - } - }, - // If either is not a valid utf8 string, just compare them byte-wise - _ => return x.eq(y) - } - } -} - -impl BytesContainer for EnvKey { - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - let &EnvKey(ref k) = self; - k.container_as_bytes() - } -} - -/// A HashMap representation of environment variables. -pub type EnvMap = HashMap; - -/// The `Command` type acts as a process builder, providing fine-grained control -/// over how a new process should be spawned. A default configuration can be -/// generated using `Command::new(program)`, where `program` gives a path to the -/// program to be executed. Additional builder methods allow the configuration -/// to be changed (for example, by adding arguments) prior to spawning: -/// -/// ``` -/// # #![feature(old_io)] -/// use std::old_io::*; -/// -/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() { -/// Ok(p) => p, -/// Err(e) => panic!("failed to execute process: {}", e), -/// }; -/// -/// let output = process.stdout.as_mut().unwrap().read_to_end(); -/// ``` -#[derive(Clone)] -pub struct Command { - // The internal data for the builder. Documented by the builder - // methods below, and serialized into rt::rtio::ProcessConfig. - program: CString, - args: Vec, - env: Option, - cwd: Option, - stdin: StdioContainer, - stdout: StdioContainer, - stderr: StdioContainer, - uid: Option, - gid: Option, - detach: bool, -} - -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take BytesContainer arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take BytesContainer as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by BytesContainer should be passed by -// reference. (Here: {new, arg, args, env}.) - -impl Command { - /// Constructs a new `Command` for launching the program at - /// path `program`, with the following default configuration: - /// - /// * No arguments to the program - /// * Inherit the current process's environment - /// * Inherit the current process's working directory - /// * A readable pipe for stdin (file descriptor 0) - /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2) - /// - /// Builder methods are provided to change these defaults and - /// otherwise configure the process. - pub fn new(program: T) -> Command { - Command { - program: CString::new(program.container_as_bytes()).unwrap(), - args: Vec::new(), - env: None, - cwd: None, - stdin: CreatePipe(true, false), - stdout: CreatePipe(false, true), - stderr: CreatePipe(false, true), - uid: None, - gid: None, - detach: false, - } - } - - /// Add an argument to pass to the program. - pub fn arg<'a, T: BytesContainer>(&'a mut self, arg: T) -> &'a mut Command { - self.args.push(CString::new(arg.container_as_bytes()).unwrap()); - self - } - - /// Add multiple arguments to pass to the program. - pub fn args<'a, T: BytesContainer>(&'a mut self, args: &[T]) -> &'a mut Command { - self.args.extend(args.iter().map(|arg| { - CString::new(arg.container_as_bytes()).unwrap() - })); - self - } - // Get a mutable borrow of the environment variable map for this `Command`. - #[allow(deprecated)] - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { - match self.env { - Some(ref mut map) => map, - None => { - // if the env is currently just inheriting from the parent's, - // materialize the parent's env into a hashtable. - self.env = Some(::env::vars().map(|(k, v)| { - (EnvKey(CString::new(k).unwrap()), - CString::new(v).unwrap()) - }).collect()); - self.env.as_mut().unwrap() - } - } - } - - /// Inserts or updates an environment variable mapping. - /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, - /// and case-sensitive on all other platforms. - pub fn env<'a, T, U>(&'a mut self, key: T, val: U) - -> &'a mut Command - where T: BytesContainer, U: BytesContainer { - let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); - let val = CString::new(val.container_as_bytes()).unwrap(); - self.get_env_map().insert(key, val); - self - } - - /// Removes an environment variable mapping. - pub fn env_remove<'a, T>(&'a mut self, key: T) -> &'a mut Command - where T: BytesContainer { - let key = EnvKey(CString::new(key.container_as_bytes()).unwrap()); - self.get_env_map().remove(&key); - self - } - - /// Sets the entire environment map for the child process. - /// - /// If the given slice contains multiple instances of an environment - /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T, U>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command - where T: BytesContainer, U: BytesContainer { - self.env = Some(env.iter().map(|&(ref k, ref v)| { - (EnvKey(CString::new(k.container_as_bytes()).unwrap()), - CString::new(v.container_as_bytes()).unwrap()) - }).collect()); - self - } - - /// Set the working directory for the child process. - pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { - self.cwd = Some(CString::new(dir.as_vec()).unwrap()); - self - } - - /// Configuration for the child process's stdin handle (file descriptor 0). - /// Defaults to `CreatePipe(true, false)` so the input can be written to. - pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stdin = cfg; - self - } - - /// Configuration for the child process's stdout handle (file descriptor 1). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stdout = cfg; - self - } - - /// Configuration for the child process's stderr handle (file descriptor 2). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { - self.stderr = cfg; - self - } - - /// Sets the child process's user id. This translates to a `setuid` call in - /// the child process. Setting this value on windows will cause the spawn to - /// fail. Failure in the `setuid` call on unix will also cause the spawn to - /// fail. - pub fn uid<'a>(&'a mut self, id: usize) -> &'a mut Command { - self.uid = Some(id); - self - } - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - pub fn gid<'a>(&'a mut self, id: usize) -> &'a mut Command { - self.gid = Some(id); - self - } - - /// Sets the child process to be spawned in a detached state. On unix, this - /// means that the child is the leader of a new process group. - pub fn detached<'a>(&'a mut self) -> &'a mut Command { - self.detach = true; - self - } - - /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> IoResult { - let (their_stdin, our_stdin) = try!(setup_io(self.stdin)); - let (their_stdout, our_stdout) = try!(setup_io(self.stdout)); - let (their_stderr, our_stderr) = try!(setup_io(self.stderr)); - - match ProcessImp::spawn(self, their_stdin, their_stdout, their_stderr) { - Err(e) => Err(e), - Ok(handle) => Ok(Process { - handle: handle, - forget: false, - exit_code: None, - exit_signal: None, - deadline: 0, - stdin: our_stdin, - stdout: our_stdout, - stderr: our_stderr, - }) - } - } - - /// Executes the command as a child process, waiting for it to finish and - /// collecting all of its output. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, core, convert)] - /// use std::old_io::Command; - /// - /// let output = match Command::new("cat").arg("foot.txt").output() { - /// Ok(output) => output, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_ref())); - /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_ref())); - /// ``` - pub fn output(&self) -> IoResult { - self.spawn().and_then(|p| p.wait_with_output()) - } - - /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io::Command; - /// - /// let status = match Command::new("ls").status() { - /// Ok(status) => status, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("process exited with: {}", status); - /// ``` - pub fn status(&self) -> IoResult { - self.spawn().and_then(|mut p| p.wait()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Command { - /// Format the program and arguments of a Command for display. Any - /// non-utf8 data is lossily converted using the utf8 replacement - /// character. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(write!(f, "{:?}", self.program)); - for arg in &self.args { - try!(write!(f, " '{:?}'", arg)); - } - Ok(()) - } -} - -fn setup_io(io: StdioContainer) -> IoResult<(Option, Option)> { - let ours; - let theirs; - match io { - Ignored => { - theirs = None; - ours = None; - } - InheritFd(fd) => { - theirs = Some(PipeStream::from_filedesc(FileDesc::new(fd, false))); - ours = None; - } - CreatePipe(readable, _writable) => { - let PipePair { reader, writer } = try!(PipeStream::pair()); - if readable { - theirs = Some(reader); - ours = Some(writer); - } else { - theirs = Some(writer); - ours = Some(reader); - } - } - } - Ok((theirs, ours)) -} - -// Allow the sys module to get access to the Command state -impl sys::process::ProcessConfig for Command { - fn program(&self) -> &CString { - &self.program - } - fn args(&self) -> &[CString] { - &self.args - } - fn env(&self) -> Option<&EnvMap> { - self.env.as_ref() - } - fn cwd(&self) -> Option<&CString> { - self.cwd.as_ref() - } - fn uid(&self) -> Option { - self.uid.clone() - } - fn gid(&self) -> Option { - self.gid.clone() - } - fn detach(&self) -> bool { - self.detach - } - -} - -/// The output of a finished process. -#[derive(PartialEq, Eq, Clone)] -pub struct ProcessOutput { - /// The status (exit code) of the process. - pub status: ProcessExit, - /// The data that the process wrote to stdout. - pub output: Vec, - /// The data that the process wrote to stderr. - pub error: Vec, -} - -/// Describes what to do with a standard io stream for a child process. -#[derive(Clone, Copy)] -pub enum StdioContainer { - /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null` - Ignored, - - /// The specified file descriptor is inherited for the stream which it is - /// specified for. Ownership of the file descriptor is *not* taken, so the - /// caller must clean it up. - InheritFd(libc::c_int), - - /// Creates a pipe for the specified file descriptor which will be created - /// when the process is spawned. - /// - /// The first boolean argument is whether the pipe is readable, and the - /// second is whether it is writable. These properties are from the view of - /// the *child* process, not the parent process. - CreatePipe(bool /* readable */, bool /* writable */), -} - -/// Describes the result of a process after it has terminated. -/// Note that Windows have no signals, so the result is usually ExitStatus. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum ProcessExit { - /// Normal termination with an exit status. - ExitStatus(isize), - - /// Termination by signal, with the signal number. - ExitSignal(isize), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ProcessExit { - /// Format a ProcessExit enum, to nicely present the information. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ExitStatus(code) => write!(f, "exit code: {}", code), - ExitSignal(code) => write!(f, "signal: {}", code), - } - } -} - -impl ProcessExit { - /// Was termination successful? Signal termination not considered a success, - /// and success is defined as a zero exit status. - pub fn success(&self) -> bool { - return self.matches_exit_status(0); - } - - /// Checks whether this ProcessExit matches the given exit status. - /// Termination by signal will never match an exit code. - pub fn matches_exit_status(&self, wanted: isize) -> bool { - *self == ExitStatus(wanted) - } -} - -impl Process { - /// Sends `signal` to another process in the system identified by `id`. - /// - /// Note that windows doesn't quite have the same model as unix, so some - /// unix signals are mapped to windows signals. Notably, unix termination - /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`. - /// - /// Additionally, a signal number of 0 can check for existence of the target - /// process. Note, though, that on some platforms signals will continue to - /// be successfully delivered if the child has exited, but not yet been - /// reaped. - pub fn kill(id: libc::pid_t, signal: isize) -> IoResult<()> { - unsafe { ProcessImp::killpid(id, signal) } - } - - /// Returns the process id of this child process - pub fn id(&self) -> libc::pid_t { self.handle.id() } - - /// Sends the specified signal to the child process, returning whether the - /// signal could be delivered or not. - /// - /// Note that signal 0 is interpreted as a poll to check whether the child - /// process is still alive or not. If an error is returned, then the child - /// process has exited. - /// - /// On some unix platforms signals will continue to be received after a - /// child has exited but not yet been reaped. In order to report the status - /// of signal delivery correctly, unix implementations may invoke - /// `waitpid()` with `WNOHANG` in order to reap the child as necessary. - /// - /// # Errors - /// - /// If the signal delivery fails, the corresponding error is returned. - pub fn signal(&mut self, signal: isize) -> IoResult<()> { - #[cfg(unix)] fn collect_status(p: &mut Process) { - // On Linux (and possibly other unices), a process that has exited will - // continue to accept signals because it is "defunct". The delivery of - // signals will only fail once the child has been reaped. For this - // reason, if the process hasn't exited yet, then we attempt to collect - // their status with WNOHANG. - if p.exit_code.is_none() { - match p.handle.try_wait() { - Some(code) => { p.exit_code = Some(code); } - None => {} - } - } - } - #[cfg(windows)] fn collect_status(_p: &mut Process) {} - - collect_status(self); - - // if the process has finished, and therefore had waitpid called, - // and we kill it, then on unix we might ending up killing a - // newer process that happens to have the same (re-used) id - if self.exit_code.is_some() { - return Err(IoError { - kind: old_io::InvalidInput, - desc: "invalid argument: can't kill an exited process", - detail: None, - }) - } - - // A successfully delivered signal that isn't 0 (just a poll for being - // alive) is recorded for windows (see wait()) - match unsafe { self.handle.kill(signal) } { - Ok(()) if signal == 0 => Ok(()), - Ok(()) => { self.exit_signal = Some(signal); Ok(()) } - Err(e) => Err(e), - } - - } - - /// Sends a signal to this child requesting that it exits. This is - /// equivalent to sending a SIGTERM on unix platforms. - pub fn signal_exit(&mut self) -> IoResult<()> { - self.signal(PleaseExitSignal) - } - - /// Sends a signal to this child forcing it to exit. This is equivalent to - /// sending a SIGKILL on unix platforms. - pub fn signal_kill(&mut self) -> IoResult<()> { - self.signal(MustDieSignal) - } - - /// Wait for the child to exit completely, returning the status that it - /// exited with. This function will continue to have the same return value - /// after it has been called at least once. - /// - /// The stdin handle to the child process will be closed before waiting. - /// - /// # Errors - /// - /// This function can fail if a timeout was previously specified via - /// `set_timeout` and the timeout expires before the child exits. - pub fn wait(&mut self) -> IoResult { - drop(self.stdin.take()); - match self.exit_code { - Some(code) => Ok(code), - None => { - let code = try!(self.handle.wait(self.deadline)); - // On windows, waitpid will never return a signal. If a signal - // was successfully delivered to the process, however, we can - // consider it as having died via a signal. - let code = match self.exit_signal { - None => code, - Some(signal) if cfg!(windows) => ExitSignal(signal), - Some(..) => code, - }; - self.exit_code = Some(code); - Ok(code) - } - } - } - - /// Sets a timeout, in milliseconds, for future calls to wait(). - /// - /// The argument specified is a relative distance into the future, in - /// milliseconds, after which any call to wait() will return immediately - /// with a timeout error, and all future calls to wait() will not block. - /// - /// A value of `None` will clear any previous timeout, and a value of `Some` - /// will override any previously set timeout. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(old_io, io)] - /// use std::old_io::{Command, IoResult}; - /// use std::old_io::process::ProcessExit; - /// - /// fn run_gracefully(prog: &str) -> IoResult { - /// let mut p = try!(Command::new("long-running-process").spawn()); - /// - /// // give the process 10 seconds to finish completely - /// p.set_timeout(Some(10_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Attempt to exit gracefully, but don't wait for it too long - /// try!(p.signal_exit()); - /// p.set_timeout(Some(1_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Well, we did our best, forcefully kill the process - /// try!(p.signal_kill()); - /// p.set_timeout(None); - /// p.wait() - /// } - /// ``` - #[unstable(feature = "io", - reason = "the type of the timeout is likely to change")] - pub fn set_timeout(&mut self, timeout_ms: Option) { - self.deadline = timeout_ms.map(|i| i + sys::timer::now()).unwrap_or(0); - } - - /// Simultaneously wait for the child to exit and collect all remaining - /// output on the stdout/stderr handles, returning a `ProcessOutput` - /// instance. - /// - /// The stdin handle to the child is closed before waiting. - /// - /// # Errors - /// - /// This function can fail for any of the same reasons that `wait()` can - /// fail. - pub fn wait_with_output(mut self) -> IoResult { - drop(self.stdin.take()); - fn read(stream: Option) -> Receiver>> { - let (tx, rx) = channel(); - match stream { - Some(stream) => { - thread::spawn(move || { - let mut stream = stream; - tx.send(stream.read_to_end()).unwrap(); - }); - } - None => tx.send(Ok(Vec::new())).unwrap() - } - rx - } - let stdout = read(self.stdout.take()); - let stderr = read(self.stderr.take()); - - let status = try!(self.wait()); - - Ok(ProcessOutput { - status: status, - output: stdout.recv().unwrap().unwrap_or(Vec::new()), - error: stderr.recv().unwrap().unwrap_or(Vec::new()), - }) - } - - /// Forgets this process, allowing it to outlive the parent - /// - /// This function will forcefully prevent calling `wait()` on the child - /// process in the destructor, allowing the child to outlive the - /// parent. Note that this operation can easily lead to leaking the - /// resources of the child process, so care must be taken when - /// invoking this method. - pub fn forget(mut self) { - self.forget = true; - } -} - -impl Drop for Process { - fn drop(&mut self) { - if self.forget { return } - - // Close all I/O before exiting to ensure that the child doesn't wait - // forever to print some text or something similar. - drop(self.stdin.take()); - drop(self.stdout.take()); - drop(self.stderr.take()); - - self.set_timeout(None); - let _ = self.wait().unwrap(); - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use old_io::{Truncate, Write, TimedOut, timer, process, FileNotFound}; - use old_io::{Reader, Writer}; - use old_path::{GenericPath, Path}; - use old_io::fs::PathExtensions; - use old_io::timer::*; - use rt::running_on_valgrind; - use str; - use super::{CreatePipe}; - use super::{InheritFd, Process, PleaseExitSignal, Command, ProcessOutput}; - use sync::mpsc::channel; - use thread; - use time::Duration; - - // FIXME(#10380) these tests should not all be ignored on android. - - #[cfg(not(target_os="android"))] - #[test] - fn smoke() { - let p = Command::new("true").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn smoke_failure() { - match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn exit_reported_right() { - let p = Command::new("false").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().matches_exit_status(1)); - drop(p.wait().clone()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn signal_reported_right() { - let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - match p.wait().unwrap() { - process::ExitSignal(9) => {}, - result => panic!("not terminated by signal 9 (instead, {})", result), - } - } - - pub fn read_all(input: &mut Reader) -> String { - input.read_to_string().unwrap() - } - - pub fn run_output(cmd: Command) -> String { - let p = cmd.spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.stdout.is_some()); - let ret = read_all(p.stdout.as_mut().unwrap() as &mut Reader); - assert!(p.wait().unwrap().success()); - return ret; - } - - #[cfg(not(target_os="android"))] - #[test] - fn stdout_works() { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(CreatePipe(false, true)); - assert_eq!(run_output(cmd), "foobar\n"); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn set_cwd_works() { - let mut cmd = Command::new("/bin/sh"); - cmd.arg("-c").arg("pwd") - .cwd(&Path::new("/")) - .stdout(CreatePipe(false, true)); - assert_eq!(run_output(cmd), "/\n"); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn stdin_works() { - let mut p = Command::new("/bin/sh") - .arg("-c").arg("read line; echo $line") - .stdin(CreatePipe(true, false)) - .stdout(CreatePipe(false, true)) - .spawn().unwrap(); - p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); - drop(p.stdin.take()); - let out = read_all(p.stdout.as_mut().unwrap() as &mut Reader); - assert!(p.wait().unwrap().success()); - assert_eq!(out, "foobar\n"); - } - - #[cfg(not(target_os="android"))] - #[test] - fn detach_works() { - let mut p = Command::new("true").detached().spawn().unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(windows)] - #[test] - fn uid_fails_on_windows() { - assert!(Command::new("test").uid(10).spawn().is_err()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn uid_works() { - use libc; - let mut p = Command::new("/bin/sh") - .arg("-c").arg("true") - .uid(unsafe { libc::getuid() as usize }) - .gid(unsafe { libc::getgid() as usize }) - .spawn().unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[cfg(all(unix, not(target_os="android")))] - #[test] - fn uid_to_root_fails() { - use libc; - - // if we're already root, this isn't a valid test. Most of the bots run - // as non-root though (android is an exception). - if unsafe { libc::getuid() == 0 } { return } - assert!(Command::new("/bin/ls").uid(0).gid(0).spawn().is_err()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_status() { - let mut status = Command::new("false").status().unwrap(); - assert!(status.matches_exit_status(1)); - - status = Command::new("true").status().unwrap(); - assert!(status.success()); - } - - #[test] - fn test_process_output_fail_to_start() { - match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind, FileNotFound), - Ok(..) => panic!() - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_output_output() { - let ProcessOutput {status, output, error} - = Command::new("echo").arg("hello").output().unwrap(); - let output_str = str::from_utf8(&output).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - // FIXME #7224 - if !running_on_valgrind() { - assert_eq!(error, Vec::new()); - } - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_process_output_error() { - let ProcessOutput {status, output, error} - = Command::new("mkdir").arg(".").output().unwrap(); - - assert!(status.matches_exit_status(1)); - assert_eq!(output, Vec::new()); - assert!(!error.is_empty()); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_finish_once() { - let mut prog = Command::new("false").spawn().unwrap(); - assert!(prog.wait().unwrap().matches_exit_status(1)); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_finish_twice() { - let mut prog = Command::new("false").spawn().unwrap(); - assert!(prog.wait().unwrap().matches_exit_status(1)); - assert!(prog.wait().unwrap().matches_exit_status(1)); - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_wait_with_output_once() { - let prog = Command::new("echo").arg("hello").spawn().unwrap(); - let ProcessOutput {status, output, error} = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(&output).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - // FIXME #7224 - if !running_on_valgrind() { - assert_eq!(error, Vec::new()); - } - } - - #[cfg(all(unix, not(target_os="android")))] - pub fn pwd_cmd() -> Command { - Command::new("pwd") - } - #[cfg(target_os="android")] - pub fn pwd_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("pwd"); - cmd - } - - #[cfg(windows)] - pub fn pwd_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("cd"); - cmd - } - - #[test] - fn test_keep_current_working_dir() { - use os; - let prog = pwd_cmd().spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); - let child_dir = Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[test] - fn test_change_working_directory() { - use os; - // test changing to the parent of os::getcwd() because we know - // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = Path::new(::env::current_dir().unwrap().to_str().unwrap()); - let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - let child_dir = Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[cfg(all(unix, not(target_os="android")))] - pub fn env_cmd() -> Command { - Command::new("env") - } - #[cfg(target_os="android")] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("set"); - cmd - } - - #[cfg(windows)] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("set"); - cmd - } - - #[cfg(not(target_os="android"))] - #[test] - fn test_inherit_env() { - use os; - if running_on_valgrind() { return; } - - let prog = env_cmd().spawn().unwrap(); - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - - let r = ::env::vars(); - for (k, v) in r { - // don't check windows magical empty-named variables - assert!(k.is_empty() || - output.contains(&format!("{}={}", k, v)), - "output doesn't contain `{}={}`\n{}", - k, v, output); - } - } - #[cfg(target_os="android")] - #[test] - fn test_inherit_env() { - use os; - if running_on_valgrind() { return; } - - let mut prog = env_cmd().spawn().unwrap(); - let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap(); - - let r = ::env::vars(); - for (k, v) in r { - // don't check android RANDOM variables - if k != "RANDOM".to_string() { - assert!(output.contains(&format!("{}={}", k, v)) || - output.contains(&format!("{}=\'{}\'", k, v))); - } - } - } - - #[test] - fn test_override_env() { - use os; - - // In some build environments (such as chrooted Nix builds), `env` can - // only be found in the explicitly-provided PATH env variable, not in - // default places such as /bin or /usr/bin. So we need to pass through - // PATH to our sub-process. - let path_val: String; - let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")]; - match ::env::var("PATH") { - Err(..) => {} - Ok(val) => { - path_val = val; - new_env.push(("PATH", &path_val)) - } - } - - let prog = env_cmd().env_set_all(&new_env).spawn().unwrap(); - let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[test] - fn test_add_to_env() { - let prog = env_cmd().env("RUN_TEST_NEW_ENV", "123").spawn().unwrap(); - let result = prog.wait_with_output().unwrap(); - let output = String::from_utf8_lossy(&result.output).to_string(); - - assert!(output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", output); - } - - #[cfg(unix)] - pub fn sleeper() -> Process { - Command::new("sleep").arg("1000").spawn().unwrap() - } - #[cfg(windows)] - pub fn sleeper() -> Process { - // There's a `timeout` command on windows, but it doesn't like having - // its output piped, so instead just ping ourselves a few times with - // gaps in between so we're sure this process is alive for awhile - Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap() - } - - #[test] - fn test_kill() { - let mut p = sleeper(); - Process::kill(p.id(), PleaseExitSignal).unwrap(); - assert!(!p.wait().unwrap().success()); - } - - #[test] - fn test_exists() { - let mut p = sleeper(); - assert!(Process::kill(p.id(), 0).is_ok()); - p.signal_kill().unwrap(); - assert!(!p.wait().unwrap().success()); - } - - #[test] - fn test_zero() { - let mut p = sleeper(); - p.signal_kill().unwrap(); - for _ in 0..20 { - if p.signal(0).is_err() { - assert!(!p.wait().unwrap().success()); - return - } - timer::sleep(Duration::milliseconds(100)); - } - panic!("never saw the child go away"); - } - - #[test] - fn wait_timeout() { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - p.set_timeout(None); - assert!(p.wait().is_ok()); - } - - #[test] - fn wait_timeout2() { - let (tx, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move|| { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - tx.send(()).unwrap(); - }); - let _t = thread::spawn(move|| { - let mut p = sleeper(); - p.set_timeout(Some(10)); - assert_eq!(p.wait().err().unwrap().kind, TimedOut); - p.signal_kill().unwrap(); - tx2.send(()).unwrap(); - }); - rx.recv().unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn forget() { - let p = sleeper(); - let id = p.id(); - p.forget(); - assert!(Process::kill(id, 0).is_ok()); - assert!(Process::kill(id, PleaseExitSignal).is_ok()); - } - - #[test] - fn dont_close_fd_on_command_spawn() { - use sys::fs; - - let path = if cfg!(windows) { - Path::new("NUL") - } else { - Path::new("/dev/null") - }; - - let fdes = match fs::open(&path, Truncate, Write) { - Ok(f) => f, - Err(_) => panic!("failed to open file descriptor"), - }; - - let mut cmd = pwd_cmd(); - let _ = cmd.stdout(InheritFd(fdes.fd())); - assert!(cmd.status().unwrap().success()); - assert!(fdes.write("extra write\n".as_bytes()).is_ok()); - } - - #[test] - #[cfg(windows)] - fn env_map_keys_ci() { - use ffi::CString; - use super::EnvKey; - let mut cmd = Command::new(""); - cmd.env("path", "foo"); - cmd.env("Path", "bar"); - let env = &cmd.env.unwrap(); - let val = env.get(&EnvKey(CString::new("PATH").unwrap())); - assert!(val.unwrap() == &CString::new("bar").unwrap()); - } -} diff --git a/src/libstd/old_io/result.rs b/src/libstd/old_io/result.rs deleted file mode 100644 index e1037f26b7..0000000000 --- a/src/libstd/old_io/result.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2013 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. - -//! Implementations of I/O traits for the IoResult type -//! -//! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `IoResult` to be used -//! as a `Reader` without unwrapping the result first. - -use clone::Clone; -use result::Result::{Ok, Err}; -use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; - -impl Writer for IoResult { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - match *self { - Ok(ref mut writer) => writer.write_all(buf), - Err(ref e) => Err((*e).clone()) - } - } - - fn flush(&mut self) -> IoResult<()> { - match *self { - Ok(ref mut writer) => writer.flush(), - Err(ref e) => Err(e.clone()), - } - } -} - -impl Reader for IoResult { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - match *self { - Ok(ref mut reader) => reader.read(buf), - Err(ref e) => Err(e.clone()), - } - } -} - -impl Seek for IoResult { - fn tell(&self) -> IoResult { - match *self { - Ok(ref seeker) => seeker.tell(), - Err(ref e) => Err(e.clone()), - } - } - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { - match *self { - Ok(ref mut seeker) => seeker.seek(pos, style), - Err(ref e) => Err(e.clone()) - } - } -} - -impl> Listener for IoResult { - fn listen(self) -> IoResult { - match self { - Ok(listener) => listener.listen(), - Err(e) => Err(e), - } - } -} - -impl Acceptor for IoResult { - type Connection = A::Connection; - fn accept(&mut self) -> IoResult { - match *self { - Ok(ref mut acceptor) => acceptor.accept(), - Err(ref e) => Err(e.clone()), - } - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - use super::super::mem::*; - use old_io::{self, Reader, Writer}; - - #[test] - fn test_option_writer() { - let mut writer: old_io::IoResult> = Ok(Vec::new()); - writer.write_all(&[0, 1, 2]).unwrap(); - writer.flush().unwrap(); - assert_eq!(writer.unwrap(), [0, 1, 2]); - } - - #[test] - fn test_option_writer_error() { - let mut writer: old_io::IoResult> = - Err(old_io::standard_error(old_io::EndOfFile)); - - match writer.write_all(&[0, 0, 0]) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - match writer.flush() { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - } - - #[test] - fn test_option_reader() { - let mut reader: old_io::IoResult = - Ok(MemReader::new(vec!(0, 1, 2, 3))); - let mut buf = [0, 0]; - reader.read(&mut buf).unwrap(); - let b: &[_] = &[0, 1]; - assert_eq!(buf, b); - } - - #[test] - fn test_option_reader_error() { - let mut reader: old_io::IoResult = - Err(old_io::standard_error(old_io::EndOfFile)); - let mut buf = []; - - match reader.read(&mut buf) { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind, old_io::EndOfFile), - } - } -} diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs deleted file mode 100644 index b4924c7b78..0000000000 --- a/src/libstd/old_io/stdio.rs +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright 2013 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. - -//! Non-blocking access to stdin, stdout, and stderr. -//! -//! This module provides bindings to the local event loop's TTY interface, using it -//! to offer synchronous but non-blocking versions of stdio. These handles can be -//! inspected for information about terminal dimensions or for related information -//! about the stream or terminal to which it is attached. -//! -//! # Examples -//! -//! ```rust -//! # #![feature(old_io)] -//! # #![allow(unused_must_use)] -//! use std::old_io; -//! use std::old_io::*; -//! -//! let mut out = old_io::stdout(); -//! out.write_all(b"Hello, world!"); -//! ``` - -use self::StdSource::*; - -use boxed; -use boxed::Box; -use cell::RefCell; -use clone::Clone; -use fmt; -use old_io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, - standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use marker::{Sync, Send}; -use libc; -use mem; -use option::Option; -use option::Option::{Some, None}; -use ops::{Deref, DerefMut, FnOnce}; -use ptr; -use result::Result::{Ok, Err}; -use rt; -use string::String; -use sys::{fs, tty}; -use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT}; -use usize; -use vec::Vec; - -// And so begins the tale of acquiring a uv handle to a stdio stream on all -// platforms in all situations. Our story begins by splitting the world into two -// categories, windows and unix. Then one day the creators of unix said let -// there be redirection! And henceforth there was redirection away from the -// console for standard I/O streams. -// -// After this day, the world split into four factions: -// -// 1. Unix with stdout on a terminal. -// 2. Unix with stdout redirected. -// 3. Windows with stdout on a terminal. -// 4. Windows with stdout redirected. -// -// Many years passed, and then one day the nation of libuv decided to unify this -// world. After months of toiling, uv created three ideas: TTY, Pipe, File. -// These three ideas propagated throughout the lands and the four great factions -// decided to settle among them. -// -// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon -// doing so, they even enhanced themselves further then their Pipe/File -// brethren, becoming the dominant powers. -// -// The group of 4, however, decided to work independently. They abandoned the -// common TTY belief throughout, and even abandoned the fledgling Pipe belief. -// The members of the 4th faction decided to only align themselves with File. -// -// tl;dr; TTY works on everything but when windows stdout is redirected, in that -// case pipe also doesn't work, but magically file does! -enum StdSource { - TTY(tty::TTY), - File(fs::FileDesc), -} - -fn src(fd: libc::c_int, _readable: bool, f: F) -> T where - F: FnOnce(StdSource) -> T, -{ - match tty::TTY::new(fd) { - Ok(tty) => f(TTY(tty)), - Err(_) => f(File(fs::FileDesc::new(fd, false))), - } -} - -thread_local! { - static LOCAL_STDOUT: RefCell>> = { - RefCell::new(None) - } -} - -struct RaceBox(BufferedReader); - -unsafe impl Send for RaceBox {} -unsafe impl Sync for RaceBox {} - -/// A synchronized wrapper around a buffered reader from stdin -#[derive(Clone)] -pub struct StdinReader { - inner: Arc>, -} - -unsafe impl Send for StdinReader {} -unsafe impl Sync for StdinReader {} - -/// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`. -pub struct StdinReaderGuard<'a> { - inner: MutexGuard<'a, RaceBox>, -} - -impl<'a> Deref for StdinReaderGuard<'a> { - type Target = BufferedReader; - - fn deref(&self) -> &BufferedReader { - &self.inner.0 - } -} - -impl<'a> DerefMut for StdinReaderGuard<'a> { - fn deref_mut(&mut self) -> &mut BufferedReader { - &mut self.inner.0 - } -} - -impl StdinReader { - /// Locks the `StdinReader`, granting the calling thread exclusive access - /// to the underlying `BufferedReader`. - /// - /// This provides access to methods like `chars` and `lines`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io)] - /// use std::old_io; - /// use std::old_io::*; - /// - /// let mut stdin = old_io::stdin(); - /// for line in stdin.lock().lines() { - /// println!("{}", line.unwrap()); - /// } - /// ``` - pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> { - StdinReaderGuard { - inner: self.inner.lock().unwrap() - } - } - - /// Like `Buffer::read_line`. - /// - /// The read is performed atomically - concurrent read calls in other - /// threads will not interleave with this one. - pub fn read_line(&mut self) -> IoResult { - self.inner.lock().unwrap().0.read_line() - } - - /// Like `Buffer::read_until`. - /// - /// The read is performed atomically - concurrent read calls in other - /// threads will not interleave with this one. - pub fn read_until(&mut self, byte: u8) -> IoResult> { - self.inner.lock().unwrap().0.read_until(byte) - } - - /// Like `Buffer::read_char`. - /// - /// The read is performed atomically - concurrent read calls in other - /// threads will not interleave with this one. - pub fn read_char(&mut self) -> IoResult { - self.inner.lock().unwrap().0.read_char() - } -} - -impl Reader for StdinReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner.lock().unwrap().0.read(buf) - } - - // We have to manually delegate all of these because the default impls call - // read more than once and we don't want those calls to interleave (or - // incur the costs of repeated locking). - - fn read_at_least(&mut self, min: usize, buf: &mut [u8]) -> IoResult { - self.inner.lock().unwrap().0.read_at_least(min, buf) - } - - fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec) -> IoResult { - self.inner.lock().unwrap().0.push_at_least(min, len, buf) - } - - fn read_to_end(&mut self) -> IoResult> { - self.inner.lock().unwrap().0.read_to_end() - } - - fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult { - self.inner.lock().unwrap().0.read_le_uint_n(nbytes) - } - - fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult { - self.inner.lock().unwrap().0.read_be_uint_n(nbytes) - } -} - -/// Creates a new handle to the stdin of the current process. -/// -/// The returned handle is a wrapper around a global `BufferedReader` shared -/// by all threads. If buffered access is not desired, the `stdin_raw` function -/// is provided to provided unbuffered access to stdin. -/// -/// See `stdout()` for more notes about this function. -pub fn stdin() -> StdinReader { - // We're following the same strategy as kimundi's lazy_static library - static mut STDIN: *mut StdinReader = 0 as *mut StdinReader; - static ONCE: Once = ONCE_INIT; - - unsafe { - ONCE.call_once(|| { - // The default buffer capacity is 64k, but apparently windows - // doesn't like 64k reads on stdin. See #13304 for details, but the - // idea is that on windows we use a slightly smaller buffer that's - // been seen to be acceptable. - let stdin = if cfg!(windows) { - BufferedReader::with_capacity(8 * 1024, stdin_raw()) - } else { - BufferedReader::new(stdin_raw()) - }; - let stdin = StdinReader { - inner: Arc::new(Mutex::new(RaceBox(stdin))) - }; - STDIN = boxed::into_raw(box stdin); - - // Make sure to free it at exit - let _ = rt::at_exit(|| { - Box::from_raw(STDIN); - STDIN = ptr::null_mut(); - }); - }); - - (*STDIN).clone() - } -} - -/// Creates a new non-blocking handle to the stdin of the current process. -/// -/// Unlike `stdin()`, the returned reader is *not* a buffered reader. -/// -/// See `stdout()` for more notes about this function. -pub fn stdin_raw() -> StdReader { - src(libc::STDIN_FILENO, true, |src| StdReader { inner: src }) -} - -/// Creates a line-buffered handle to the stdout of the current process. -/// -/// Note that this is a fairly expensive operation in that at least one memory -/// allocation is performed. Additionally, this must be called from a runtime -/// task context because the stream returned will be a non-blocking object using -/// the local scheduler to perform the I/O. -/// -/// Care should be taken when creating multiple handles to an output stream for -/// a single process. While usage is still safe, the output may be surprising if -/// no synchronization is performed to ensure a sane output. -pub fn stdout() -> LineBufferedWriter { - LineBufferedWriter::new(stdout_raw()) -} - -/// Creates an unbuffered handle to the stdout of the current process -/// -/// See notes in `stdout()` for more information. -pub fn stdout_raw() -> StdWriter { - src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src }) -} - -/// Creates a line-buffered handle to the stderr of the current process. -/// -/// See `stdout()` for notes about this function. -pub fn stderr() -> LineBufferedWriter { - LineBufferedWriter::new(stderr_raw()) -} - -/// Creates an unbuffered handle to the stderr of the current process -/// -/// See notes in `stdout()` for more information. -pub fn stderr_raw() -> StdWriter { - src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src }) -} - -/// Resets the task-local stdout handle to the specified writer -/// -/// This will replace the current task's stdout handle, returning the old -/// handle. All future calls to `print` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new tasks; the default -/// output handle is to the process's stdout stream. -pub fn set_stdout(stdout: Box) -> Option> { - let mut new = Some(stdout); - LOCAL_STDOUT.with(|slot| { - mem::replace(&mut *slot.borrow_mut(), new.take()) - }).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) -} - -/// Resets the task-local stderr handle to the specified writer -/// -/// This will replace the current task's stderr handle, returning the old -/// handle. Currently, the stderr handle is used for printing panic messages -/// during task panic. -/// -/// Note that this does not need to be called for all new tasks; the default -/// output handle is to the process's stderr stream. -#[unstable(feature = "old_io")] -#[deprecated(since = "1.0.0", reason = "replaced with std::io::set_panic")] -pub fn set_stderr(_stderr: Box) -> Option> { - None -} - -// Helper to access the local task's stdout handle -// -// Note that this is not a safe function to expose because you can create an -// aliased pointer very easily: -// -// with_task_stdout(|io1| { -// with_task_stdout(|io2| { -// // io1 aliases io2 -// }) -// }) -fn with_task_stdout(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> { - let mut my_stdout: Box = LOCAL_STDOUT.with(|slot| { - slot.borrow_mut().take() - }).unwrap_or_else(|| { - box stdout() - }); - let result = f(&mut *my_stdout); - let mut var = Some(my_stdout); - LOCAL_STDOUT.with(|slot| { - *slot.borrow_mut() = var.take(); - }); - match result { - Ok(()) => {} - Err(e) => panic!("failed printing to stdout: {:?}", e), - } -} - -/// Flushes the local task's stdout handle. -/// -/// By default, this stream is a line-buffering stream, so flushing may be -/// necessary to ensure that all output is printed to the screen (if there are -/// no newlines printed). -/// -/// Note that logging macros do not use this stream. Using the logging macros -/// will emit output to stderr, and while they are line buffered the log -/// messages are always terminated in a newline (no need to flush). -pub fn flush() { - with_task_stdout(|io| io.flush()) -} - -/// Prints a string to the stdout of the current process. No newline is emitted -/// after the string is printed. -pub fn print(s: &str) { - with_task_stdout(|io| io.write_all(s.as_bytes())) -} - -/// Prints a string to the stdout of the current process. A literal -/// `\n` character is printed to the console after the string. -pub fn println(s: &str) { - with_task_stdout(|io| { - io.write_all(s.as_bytes()).and_then(|()| io.write_all(&[b'\n'])) - }) -} - -/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible -/// with the `format_args!` macro. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn print_args(fmt: fmt::Arguments) { - with_task_stdout(|io| write!(io, "{}", fmt)) -} - -/// Similar to `println`, but takes a `fmt::Arguments` structure to be -/// compatible with the `format_args!` macro. -#[stable(feature = "rust1", since = "1.0.0")] -pub fn println_args(fmt: fmt::Arguments) { - with_task_stdout(|io| writeln!(io, "{}", fmt)) -} - -/// Representation of a reader of a standard input stream -pub struct StdReader { - inner: StdSource -} - -impl StdReader { - /// Returns whether this stream is attached to a TTY instance or not. - pub fn isatty(&self) -> bool { - match self.inner { - TTY(..) => true, - File(..) => false, - } - } -} - -impl Reader for StdReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = match self.inner { - TTY(ref mut tty) => { - // Flush the task-local stdout so that weird issues like a - // print!'d prompt not being shown until after the user hits - // enter. - flush(); - tty.read(buf).map(|i| i as usize) - }, - File(ref mut file) => file.read(buf).map(|i| i as usize), - }; - match ret { - // When reading a piped stdin, libuv will return 0-length reads when - // stdin reaches EOF. For pretty much all other streams it will - // return an actual EOF error, but apparently for stdin it's a - // little different. Hence, here we convert a 0 length read to an - // end-of-file indicator so the caller knows to stop reading. - Ok(0) => { Err(standard_error(EndOfFile)) } - ret @ Ok(..) | ret @ Err(..) => ret, - } - } -} - -/// Representation of a writer to a standard output stream -pub struct StdWriter { - inner: StdSource -} - -unsafe impl Send for StdWriter {} -unsafe impl Sync for StdWriter {} - -impl StdWriter { - /// Gets the size of this output window, if possible. This is typically used - /// when the writer is attached to something like a terminal, this is used - /// to fetch the dimensions of the terminal. - /// - /// If successful, returns `Ok((width, height))`. - /// - /// # Error - /// - /// This function will return an error if the output stream is not actually - /// connected to a TTY instance, or if querying the TTY instance fails. - pub fn winsize(&mut self) -> IoResult<(isize, isize)> { - match self.inner { - TTY(ref mut tty) => { - tty.get_winsize() - } - File(..) => { - Err(IoError { - kind: OtherIoError, - desc: "stream is not a tty", - detail: None, - }) - } - } - } - - /// Controls whether this output stream is a "raw stream" or simply a normal - /// stream. - /// - /// # Error - /// - /// This function will return an error if the output stream is not actually - /// connected to a TTY instance, or if querying the TTY instance fails. - pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { - match self.inner { - TTY(ref mut tty) => { - tty.set_raw(raw) - } - File(..) => { - Err(IoError { - kind: OtherIoError, - desc: "stream is not a tty", - detail: None, - }) - } - } - } - - /// Returns whether this stream is attached to a TTY instance or not. - pub fn isatty(&self) -> bool { - match self.inner { - TTY(..) => true, - File(..) => false, - } - } -} - -impl Writer for StdWriter { - fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { - // As with stdin on windows, stdout often can't handle writes of large - // sizes. For an example, see #14940. For this reason, chunk the output - // buffer on windows, but on unix we can just write the whole buffer all - // at once. - // - // For some other references, it appears that this problem has been - // encountered by others [1] [2]. We choose the number 8KB just because - // libuv does the same. - // - // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 - // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html - let max_size = if cfg!(windows) {8192} else {usize::MAX}; - for chunk in buf.chunks(max_size) { - try!(match self.inner { - TTY(ref mut tty) => tty.write(chunk), - File(ref mut file) => file.write(chunk), - }) - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use super::*; - use sync::mpsc::channel; - use thread; - - #[test] - fn smoke() { - // Just make sure we can acquire handles - stdin(); - stdout(); - stderr(); - } -} diff --git a/src/libstd/old_io/tempfile.rs b/src/libstd/old_io/tempfile.rs deleted file mode 100644 index 94faa5540b..0000000000 --- a/src/libstd/old_io/tempfile.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2013 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. - -//! Temporary files and directories -#![allow(deprecated)] // rand - -use env; -use iter::Iterator; -use old_io::{fs, IoError, IoErrorKind, IoResult}; -use old_io; -use ops::Drop; -use option::Option::{None, Some}; -use option::Option; -use old_path::{Path, GenericPath}; -use rand::{Rng, thread_rng}; -use result::Result::{Ok, Err}; -use string::String; - -/// A wrapper for a path to temporary directory implementing automatic -/// scope-based deletion. -/// -/// # Examples -/// -/// ```no_run -/// # #![feature(old_io, old_path)] -/// use std::old_io::*; -/// use std::old_path::{Path, GenericPath}; -/// -/// { -/// // create a temporary directory -/// let tmpdir = match TempDir::new("myprefix") { -/// Ok(dir) => dir, -/// Err(e) => panic!("couldn't create temporary directory: {}", e) -/// }; -/// -/// // get the path of the temporary directory without affecting the wrapper -/// let tmppath = tmpdir.path(); -/// -/// println!("The path of temporary directory is {}", tmppath.display()); -/// -/// // the temporary directory is automatically removed when tmpdir goes -/// // out of scope at the end of the block -/// } -/// { -/// // create a temporary directory, this time using a custom path -/// let tmpdir = match TempDir::new_in(&Path::new("/tmp/best/custom/path"), "myprefix") { -/// Ok(dir) => dir, -/// Err(e) => panic!("couldn't create temporary directory: {}", e) -/// }; -/// -/// // get the path of the temporary directory and disable automatic deletion in the wrapper -/// let tmppath = tmpdir.into_inner(); -/// -/// println!("The path of the not-so-temporary directory is {}", tmppath.display()); -/// -/// // the temporary directory is not removed here -/// // because the directory is detached from the wrapper -/// } -/// { -/// // create a temporary directory -/// let tmpdir = match TempDir::new("myprefix") { -/// Ok(dir) => dir, -/// Err(e) => panic!("couldn't create temporary directory: {}", e) -/// }; -/// -/// // close the temporary directory manually and check the result -/// match tmpdir.close() { -/// Ok(_) => println!("success!"), -/// Err(e) => panic!("couldn't remove temporary directory: {}", e) -/// }; -/// } -/// ``` -pub struct TempDir { - path: Option, - disarmed: bool -} - -// How many times should we (re)try finding an unused random name? It should be -// enough that an attacker will run out of luck before we run out of patience. -const NUM_RETRIES: u32 = 1 << 31; -// How many characters should we include in a random file name? It needs to -// be enough to dissuade an attacker from trying to preemptively create names -// of that length, but not so huge that we unnecessarily drain the random number -// generator of entropy. -const NUM_RAND_CHARS: usize = 12; - -impl TempDir { - /// Attempts to make a temporary directory inside of `tmpdir` whose name - /// will have the prefix `prefix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - #[allow(deprecated)] - pub fn new_in(tmpdir: &Path, prefix: &str) -> IoResult { - if !tmpdir.is_absolute() { - let cur_dir = ::env::current_dir().unwrap(); - let cur_dir = Path::new(cur_dir.to_str().unwrap()); - return TempDir::new_in(&cur_dir.join(tmpdir), prefix); - } - - let mut rng = thread_rng(); - for _ in 0..NUM_RETRIES { - let suffix: String = rng.gen_ascii_chars().take(NUM_RAND_CHARS).collect(); - let leaf = if prefix.len() > 0 { - format!("{}.{}", prefix, suffix) - } else { - // If we're given an empty string for a prefix, then creating a - // directory starting with "." would lead to it being - // semi-invisible on some systems. - suffix - }; - let path = tmpdir.join(leaf); - match fs::mkdir(&path, old_io::USER_RWX) { - Ok(_) => return Ok(TempDir { path: Some(path), disarmed: false }), - Err(IoError{kind:IoErrorKind::PathAlreadyExists,..}) => (), - Err(e) => return Err(e) - } - } - - return Err(IoError{ - kind: IoErrorKind::PathAlreadyExists, - desc:"Exhausted", - detail: None}); - } - - /// Attempts to make a temporary directory inside of `os::tmpdir()` whose - /// name will have the prefix `prefix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - #[allow(deprecated)] - pub fn new(prefix: &str) -> IoResult { - let tmp = Path::new(::env::temp_dir().to_str().unwrap()); - TempDir::new_in(&tmp, prefix) - } - - /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. - /// This discards the wrapper so that the automatic deletion of the - /// temporary directory is prevented. - pub fn into_inner(self) -> Path { - let mut tmpdir = self; - tmpdir.path.take().unwrap() - } - - /// Access the wrapped `std::path::Path` to the temporary directory. - pub fn path<'a>(&'a self) -> &'a Path { - self.path.as_ref().unwrap() - } - - /// Close and remove the temporary directory - /// - /// Although `TempDir` removes the directory on drop, in the destructor - /// any errors are ignored. To detect errors cleaning up the temporary - /// directory, call `close` instead. - pub fn close(mut self) -> IoResult<()> { - self.cleanup_dir() - } - - fn cleanup_dir(&mut self) -> IoResult<()> { - assert!(!self.disarmed); - self.disarmed = true; - match self.path { - Some(ref p) => { - fs::rmdir_recursive(p) - } - None => Ok(()) - } - } -} - -impl Drop for TempDir { - fn drop(&mut self) { - if !self.disarmed { - let _ = self.cleanup_dir(); - } - } -} - -// the tests for this module need to change the path using change_dir, -// and this doesn't play nicely with other tests so these unit tests are located -// in src/test/run-pass/tempfile.rs diff --git a/src/libstd/old_io/test.rs b/src/libstd/old_io/test.rs deleted file mode 100644 index 312e1c814d..0000000000 --- a/src/libstd/old_io/test.rs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2013 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. - -//! Various utility functions useful for writing I/O tests - -use prelude::v1::*; - -use env; -use libc; -use old_io::net::ip::*; -use old_path::{Path, GenericPath}; -use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -/// Get a port number, starting at 9600, for use in tests -pub fn next_test_port() -> u16 { - static NEXT_OFFSET: AtomicUsize = ATOMIC_USIZE_INIT; - base_port() + NEXT_OFFSET.fetch_add(1, Ordering::Relaxed) as u16 -} - -// iOS has a pretty long tmpdir path which causes pipe creation -// to like: invalid argument: path must be smaller than SUN_LEN -fn next_test_unix_socket() -> String { - static COUNT: AtomicUsize = ATOMIC_USIZE_INIT; - // base port and pid are an attempt to be unique between multiple - // test-runners of different configurations running on one - // buildbot, the count is to be unique within this executable. - format!("rust-test-unix-path-{}-{}-{}", - base_port(), - unsafe {libc::getpid()}, - COUNT.fetch_add(1, Ordering::Relaxed)) -} - -/// Get a temporary path which could be the location of a unix socket -#[cfg(not(target_os = "ios"))] -#[allow(deprecated)] -pub fn next_test_unix() -> Path { - let string = next_test_unix_socket(); - if cfg!(unix) { - Path::new(::env::temp_dir().to_str().unwrap()).join(string) - } else { - Path::new(format!("{}{}", r"\\.\pipe\", string)) - } -} - -/// Get a temporary path which could be the location of a unix socket -#[cfg(target_os = "ios")] -pub fn next_test_unix() -> Path { - Path::new(format!("/var/tmp/{}", next_test_unix_socket())) -} - -/// Get a unique IPv4 localhost:port pair starting at 9600 -pub fn next_test_ip4() -> SocketAddr { - SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() } -} - -/// Get a unique IPv6 localhost:port pair starting at 9600 -pub fn next_test_ip6() -> SocketAddr { - SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() } -} - -/* -XXX: Welcome to MegaHack City. - -The bots run multiple builds at the same time, and these builds -all want to use ports. This function figures out which workspace -it is running in and assigns a port range based on it. -*/ -fn base_port() -> u16 { - - let base = 9600; - let range = 1000; - - let bases = [ - ("32-opt", base + range * 1), - ("32-nopt", base + range * 2), - ("64-opt", base + range * 3), - ("64-nopt", base + range * 4), - ("64-opt-vg", base + range * 5), - ("all-opt", base + range * 6), - ("snap3", base + range * 7), - ("dist", base + range * 8) - ]; - - // FIXME (#9639): This needs to handle non-utf8 paths - let path = env::current_dir().unwrap(); - let path_s = path.to_str().unwrap(); - - let mut final_base = base; - - for &(dir, base) in &bases { - if path_s.contains(dir) { - final_base = base; - break; - } - } - - return final_base; -} - -/// Raises the file descriptor limit when running tests if necessary -pub fn raise_fd_limit() { - unsafe { darwin_fd_limit::raise_fd_limit() } -} - -/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the rlimit -/// maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low for our -/// multithreaded scheduler testing, depending on the number of cores available. -/// -/// This fixes issue #7772. -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[allow(non_camel_case_types)] -mod darwin_fd_limit { - use libc; - type rlim_t = libc::uint64_t; - #[repr(C)] - struct rlimit { - rlim_cur: rlim_t, - rlim_max: rlim_t - } - extern { - // name probably doesn't need to be mut, but the C function doesn't specify const - fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint, - oldp: *mut libc::c_void, oldlenp: *mut libc::size_t, - newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int; - fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int; - fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int; - } - static CTL_KERN: libc::c_int = 1; - static KERN_MAXFILESPERPROC: libc::c_int = 29; - static RLIMIT_NOFILE: libc::c_int = 8; - - pub unsafe fn raise_fd_limit() { - // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc - // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value. - use ptr::null_mut; - use mem::size_of_val; - use io; - - // Fetch the kern.maxfilesperproc value - let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC]; - let mut maxfiles: libc::c_int = 0; - let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t; - if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size, - null_mut(), 0) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling sysctl: {}", err); - } - - // Fetch the current resource limits - let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0}; - if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling getrlimit: {}", err); - } - - // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit - rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max); - - // Set our newly-increased resource limit - if setrlimit(RLIMIT_NOFILE, &rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling setrlimit: {}", err); - } - } -} - -#[cfg(not(any(target_os = "macos", target_os = "ios")))] -mod darwin_fd_limit { - pub unsafe fn raise_fd_limit() {} -} diff --git a/src/libstd/old_io/timer.rs b/src/libstd/old_io/timer.rs deleted file mode 100644 index f8cba04444..0000000000 --- a/src/libstd/old_io/timer.rs +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2013 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. - -//! Synchronous Timers -//! -//! This module exposes the functionality to create timers, block the current task, -//! and create receivers which will receive notifications after a period of time. - -// FIXME: These functions take Durations but only pass ms to the backend impls. - -use boxed::Box; -use sync::mpsc::{Receiver, Sender, channel}; -use time::Duration; -use old_io::IoResult; -use sys::timer::Callback; -use sys::timer::Timer as TimerImp; - -/// A synchronous timer object -/// -/// Values of this type can be used to put the current task to sleep for a -/// period of time. Handles to this timer can also be created in the form of -/// receivers which will receive notifications over time. -/// -/// # Examples -/// -/// ``` -/// # #![feature(old_io, std_misc)] -/// # fn foo() { -/// use std::old_io::Timer; -/// use std::time::Duration; -/// -/// let mut timer = Timer::new().unwrap(); -/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile -/// -/// let timeout = timer.oneshot(Duration::milliseconds(10)); -/// // do some work -/// timeout.recv().unwrap(); // wait for the timeout to expire -/// -/// let periodic = timer.periodic(Duration::milliseconds(10)); -/// loop { -/// periodic.recv().unwrap(); -/// // this loop is only executed once every 10ms -/// } -/// # } -/// ``` -/// -/// If only sleeping is necessary, then a convenience API is provided through -/// the `old_io::timer` module. -/// -/// ``` -/// # #![feature(old_io, std_misc)] -/// # fn foo() { -/// use std::old_io::timer; -/// use std::time::Duration; -/// -/// // Put this task to sleep for 5 seconds -/// timer::sleep(Duration::seconds(5)); -/// # } -/// ``` -pub struct Timer { - inner: TimerImp, -} - -struct TimerCallback { tx: Sender<()> } - -/// Sleep the current task for the specified duration. -/// -/// When provided a zero or negative `duration`, the function will -/// return immediately. -pub fn sleep(duration: Duration) { - let timer = Timer::new(); - let mut timer = timer.ok().expect("timer::sleep: could not create a Timer"); - - timer.sleep(duration) -} - -impl Timer { - /// Creates a new timer which can be used to put the current task to sleep - /// for a number of milliseconds, or to possibly create channels which will - /// get notified after an amount of time has passed. - pub fn new() -> IoResult { - TimerImp::new().map(|t| Timer { inner: t }) - } - - /// Blocks the current task for the specified duration. - /// - /// Note that this function will cause any other receivers for this timer to - /// be invalidated (the other end will be closed). - /// - /// When provided a zero or negative `duration`, the function will - /// return immediately. - pub fn sleep(&mut self, duration: Duration) { - // Short-circuit the timer backend for 0 duration - let ms = in_ms_u64(duration); - if ms == 0 { return } - self.inner.sleep(ms); - } - - /// Creates a oneshot receiver which will have a notification sent when - /// the specified duration has elapsed. - /// - /// This does *not* block the current task, but instead returns immediately. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, std_misc)] - /// use std::old_io::Timer; - /// use std::time::Duration; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10)); - /// - /// for _ in 0..100 { /* do work */ } - /// - /// // blocks until 10 ms after the `oneshot` call - /// ten_milliseconds.recv().unwrap(); - /// ``` - /// - /// ``` - /// # #![feature(old_io, std_misc)] - /// use std::old_io::Timer; - /// use std::time::Duration; - /// - /// // Incorrect, method chaining-style: - /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5)); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv().unwrap() - /// ``` - /// - /// When provided a zero or negative `duration`, the message will - /// be sent immediately. - pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { - let (tx, rx) = channel(); - // Short-circuit the timer backend for 0 duration - if in_ms_u64(duration) != 0 { - self.inner.oneshot(in_ms_u64(duration), Box::new(TimerCallback { tx: tx })); - } else { - tx.send(()).unwrap(); - } - return rx - } - - /// Creates a receiver which will have a continuous stream of notifications - /// being sent each time the specified duration has elapsed. - /// - /// This does *not* block the current task, but instead returns - /// immediately. The first notification will not be received immediately, - /// but rather after the first duration. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_io, std_misc)] - /// use std::old_io::Timer; - /// use std::time::Duration; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10)); - /// - /// for _ in 0..100 { /* do work */ } - /// - /// // blocks until 10 ms after the `periodic` call - /// ten_milliseconds.recv().unwrap(); - /// - /// for _ in 0..100 { /* do work */ } - /// - /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the - /// // previous `recv`) - /// ten_milliseconds.recv().unwrap(); - /// ``` - /// - /// ``` - /// # #![feature(old_io, std_misc)] - /// use std::old_io::Timer; - /// use std::time::Duration; - /// - /// // Incorrect, method chaining-style. - /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5)); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv().unwrap() - /// ``` - /// - /// When provided a zero or negative `duration`, the messages will - /// be sent without delay. - pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { - let ms = in_ms_u64(duration); - // FIXME: The backend implementations don't ever send a message - // if given a 0 ms duration. Temporarily using 1ms. It's - // not clear what use a 0ms period is anyway... - let ms = if ms == 0 { 1 } else { ms }; - let (tx, rx) = channel(); - self.inner.period(ms, Box::new(TimerCallback { tx: tx })); - return rx - } -} - -impl Callback for TimerCallback { - fn call(&mut self) { - let _ = self.tx.send(()); - } -} - -fn in_ms_u64(d: Duration) -> u64 { - let ms = d.num_milliseconds(); - if ms < 0 { return 0 }; - return ms as u64; -} - -#[cfg(test)] -mod test { - use super::Timer; - use thread; - use time::Duration; - - #[test] - fn test_timer_send() { - let mut timer = Timer::new().unwrap(); - thread::spawn(move || timer.sleep(Duration::milliseconds(1))); - } - - #[test] - fn test_io_timer_sleep_simple() { - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(1)); - } - - #[test] - fn test_io_timer_sleep_oneshot() { - let mut timer = Timer::new().unwrap(); - timer.oneshot(Duration::milliseconds(1)).recv().unwrap(); - } - - #[test] - fn test_io_timer_sleep_oneshot_forget() { - let mut timer = Timer::new().unwrap(); - timer.oneshot(Duration::milliseconds(100000000)); - } - - #[test] - fn oneshot_twice() { - let mut timer = Timer::new().unwrap(); - let rx1 = timer.oneshot(Duration::milliseconds(10000)); - let rx = timer.oneshot(Duration::milliseconds(1)); - rx.recv().unwrap(); - assert!(rx1.recv().is_err()); - } - - #[test] - fn test_io_timer_oneshot_then_sleep() { - let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot(Duration::milliseconds(100000000)); - timer.sleep(Duration::milliseconds(1)); // this should invalidate rx - - assert!(rx.recv().is_err()); - } - - #[test] - fn test_io_timer_sleep_periodic() { - let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(Duration::milliseconds(1)); - rx.recv().unwrap(); - rx.recv().unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn test_io_timer_sleep_periodic_forget() { - let mut timer = Timer::new().unwrap(); - timer.periodic(Duration::milliseconds(100000000)); - } - - #[test] - fn test_io_timer_sleep_standalone() { - super::sleep(Duration::milliseconds(1)) - } - - #[test] - fn oneshot() { - let mut timer = Timer::new().unwrap(); - - let rx = timer.oneshot(Duration::milliseconds(1)); - rx.recv().unwrap(); - assert!(rx.recv().is_err()); - - let rx = timer.oneshot(Duration::milliseconds(1)); - rx.recv().unwrap(); - assert!(rx.recv().is_err()); - } - - #[test] - fn test_override() { - let mut timer = Timer::new().unwrap(); - let orx = timer.oneshot(Duration::milliseconds(100)); - let prx = timer.periodic(Duration::milliseconds(100)); - timer.sleep(Duration::milliseconds(1)); - assert!(orx.recv().is_err()); - assert!(prx.recv().is_err()); - timer.oneshot(Duration::milliseconds(1)).recv().unwrap(); - } - - #[test] - fn period() { - let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(Duration::milliseconds(1)); - rx.recv().unwrap(); - rx.recv().unwrap(); - let rx2 = timer.periodic(Duration::milliseconds(1)); - rx2.recv().unwrap(); - rx2.recv().unwrap(); - } - - #[test] - fn sleep() { - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(1)); - timer.sleep(Duration::milliseconds(1)); - } - - #[test] - #[should_panic] - fn oneshot_fail() { - let mut timer = Timer::new().unwrap(); - let _rx = timer.oneshot(Duration::milliseconds(1)); - panic!(); - } - - #[test] - #[should_panic] - fn period_fail() { - let mut timer = Timer::new().unwrap(); - let _rx = timer.periodic(Duration::milliseconds(1)); - panic!(); - } - - #[test] - #[should_panic] - fn normal_fail() { - let _timer = Timer::new().unwrap(); - panic!(); - } - - #[test] - fn closing_channel_during_drop_doesnt_kill_everything() { - // see issue #10375 - let mut timer = Timer::new().unwrap(); - let timer_rx = timer.periodic(Duration::milliseconds(1000)); - - thread::spawn(move|| { - let _ = timer_rx.recv(); - }); - - // when we drop the TimerWatcher we're going to destroy the channel, - // which must wake up the task on the other end - } - - #[test] - fn reset_doesnt_switch_tasks() { - // similar test to the one above. - let mut timer = Timer::new().unwrap(); - let timer_rx = timer.periodic(Duration::milliseconds(1000)); - - thread::spawn(move|| { - let _ = timer_rx.recv(); - }); - - timer.oneshot(Duration::milliseconds(1)); - } - - #[test] - fn reset_doesnt_switch_tasks2() { - // similar test to the one above. - let mut timer = Timer::new().unwrap(); - let timer_rx = timer.periodic(Duration::milliseconds(1000)); - - thread::spawn(move|| { - let _ = timer_rx.recv(); - }); - - timer.sleep(Duration::milliseconds(1)); - } - - #[test] - fn sender_goes_away_oneshot() { - let rx = { - let mut timer = Timer::new().unwrap(); - timer.oneshot(Duration::milliseconds(1000)) - }; - assert!(rx.recv().is_err()); - } - - #[test] - fn sender_goes_away_period() { - let rx = { - let mut timer = Timer::new().unwrap(); - timer.periodic(Duration::milliseconds(1000)) - }; - assert!(rx.recv().is_err()); - } - - #[test] - fn receiver_goes_away_oneshot() { - let mut timer1 = Timer::new().unwrap(); - timer1.oneshot(Duration::milliseconds(1)); - let mut timer2 = Timer::new().unwrap(); - // while sleeping, the previous timer should fire and not have its - // callback do something terrible. - timer2.sleep(Duration::milliseconds(2)); - } - - #[test] - fn receiver_goes_away_period() { - let mut timer1 = Timer::new().unwrap(); - timer1.periodic(Duration::milliseconds(1)); - let mut timer2 = Timer::new().unwrap(); - // while sleeping, the previous timer should fire and not have its - // callback do something terrible. - timer2.sleep(Duration::milliseconds(2)); - } - - #[test] - fn sleep_zero() { - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(0)); - } - - #[test] - fn sleep_negative() { - let mut timer = Timer::new().unwrap(); - timer.sleep(Duration::milliseconds(-1000000)); - } - - #[test] - fn oneshot_zero() { - let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot(Duration::milliseconds(0)); - rx.recv().unwrap(); - } - - #[test] - fn oneshot_negative() { - let mut timer = Timer::new().unwrap(); - let rx = timer.oneshot(Duration::milliseconds(-1000000)); - rx.recv().unwrap(); - } - - #[test] - fn periodic_zero() { - let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(Duration::milliseconds(0)); - rx.recv().unwrap(); - rx.recv().unwrap(); - rx.recv().unwrap(); - rx.recv().unwrap(); - } - - #[test] - fn periodic_negative() { - let mut timer = Timer::new().unwrap(); - let rx = timer.periodic(Duration::milliseconds(-1000000)); - rx.recv().unwrap(); - rx.recv().unwrap(); - rx.recv().unwrap(); - rx.recv().unwrap(); - } - -} diff --git a/src/libstd/old_io/util.rs b/src/libstd/old_io/util.rs deleted file mode 100644 index 818c8e76d6..0000000000 --- a/src/libstd/old_io/util.rs +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright 2013 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. - -//! Utility implementations of Reader and Writer - -#![allow(deprecated)] - -use prelude::v1::*; -use cmp; -use old_io::{self, Reader, Writer, Buffer}; -use slice::bytes::MutableByteVector; - -/// Wraps a `Reader`, limiting the number of bytes that can be read from it. -#[derive(Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::Take")] -#[unstable(feature = "old_io")] -pub struct LimitReader { - limit: usize, - inner: R -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Take")] -#[unstable(feature = "old_io")] -impl LimitReader { - /// Creates a new `LimitReader` - #[deprecated(since = "1.0.0", reason = "use std::io's take method instead")] - #[unstable(feature = "old_io")] - pub fn new(r: R, limit: usize) -> LimitReader { - LimitReader { limit: limit, inner: r } - } - - /// Consumes the `LimitReader`, returning the underlying `Reader`. - pub fn into_inner(self) -> R { self.inner } - - /// Returns the number of bytes that can be read before the `LimitReader` - /// will return EOF. - /// - /// # Note - /// - /// The reader may reach EOF after reading fewer bytes than indicated by - /// this method if the underlying reader reaches EOF. - pub fn limit(&self) -> usize { self.limit } -} - -#[deprecated(since = "1.0.0", reason = "use std::io's take method instead")] -#[unstable(feature = "old_io")] -impl Reader for LimitReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - if self.limit == 0 { - return Err(old_io::standard_error(old_io::EndOfFile)); - } - - let len = cmp::min(self.limit, buf.len()); - let res = self.inner.read(&mut buf[..len]); - match res { - Ok(len) => self.limit -= len, - _ => {} - } - res - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io's take method instead")] -#[unstable(feature = "old_io")] -impl Buffer for LimitReader { - fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> { - let amt = try!(self.inner.fill_buf()); - let buf = &amt[..cmp::min(amt.len(), self.limit)]; - if buf.len() == 0 { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(buf) - } - } - - fn consume(&mut self, amt: usize) { - // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt, self.limit); - self.limit -= amt; - self.inner.consume(amt); - } - -} - -/// A `Writer` which ignores bytes written to it, like /dev/null. -#[derive(Copy, Clone, Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")] -#[unstable(feature = "old_io")] -pub struct NullWriter; - -#[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")] -#[unstable(feature = "old_io")] -impl Writer for NullWriter { - #[inline] - fn write_all(&mut self, _buf: &[u8]) -> old_io::IoResult<()> { Ok(()) } -} - -/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. -#[derive(Copy, Clone, Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")] -#[unstable(feature = "old_io")] -pub struct ZeroReader; - -#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")] -#[unstable(feature = "old_io")] -impl Reader for ZeroReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - buf.set_memory(0); - Ok(buf.len()) - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")] -#[unstable(feature = "old_io")] -impl Buffer for ZeroReader { - fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> { - static DATA: [u8; 64] = [0; 64]; - Ok(&DATA) - } - - fn consume(&mut self, _amt: usize) {} -} - -/// A `Reader` which is always at EOF, like /dev/null. -#[derive(Copy, Clone, Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")] -#[unstable(feature = "old_io")] -pub struct NullReader; - -#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")] -#[unstable(feature = "old_io")] -impl Reader for NullReader { - #[inline] - fn read(&mut self, _buf: &mut [u8]) -> old_io::IoResult { - Err(old_io::standard_error(old_io::EndOfFile)) - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")] -#[unstable(feature = "old_io")] -impl Buffer for NullReader { - fn fill_buf<'a>(&'a mut self) -> old_io::IoResult<&'a [u8]> { - Err(old_io::standard_error(old_io::EndOfFile)) - } - fn consume(&mut self, _amt: usize) {} -} - -/// A `Writer` which multiplexes writes to a set of `Writer`s. -/// -/// The `Writer`s are delegated to in order. If any `Writer` returns an error, -/// that error is returned immediately and remaining `Writer`s are not called. -#[derive(Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::Broadcast instead")] -#[unstable(feature = "old_io")] -pub struct MultiWriter { - writers: Vec -} - -impl MultiWriter where W: Writer { - /// Creates a new `MultiWriter` - #[deprecated(since = "1.0.0", reason = "use std::io's broadcast method instead")] - #[unstable(feature = "old_io")] - pub fn new(writers: Vec) -> MultiWriter { - MultiWriter { writers: writers } - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Broadcast instead")] -#[unstable(feature = "old_io")] -impl Writer for MultiWriter where W: Writer { - #[inline] - fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { - for writer in &mut self.writers { - try!(writer.write_all(buf)); - } - Ok(()) - } - - #[inline] - fn flush(&mut self) -> old_io::IoResult<()> { - for writer in &mut self.writers { - try!(writer.flush()); - } - Ok(()) - } -} - -/// A `Reader` which chains input from multiple `Reader`s, reading each to -/// completion before moving onto the next. -#[derive(Clone, Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::Chain instead")] -#[unstable(feature = "old_io")] -pub struct ChainedReader { - readers: I, - cur_reader: Option, -} - -impl> ChainedReader { - /// Creates a new `ChainedReader` - #[deprecated(since = "1.0.0", reason = "use std::io's chain method instead")] - #[unstable(feature = "old_io")] - pub fn new(mut readers: I) -> ChainedReader { - let r = readers.next(); - ChainedReader { readers: readers, cur_reader: r } - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Chain instead")] -#[unstable(feature = "old_io")] -impl> Reader for ChainedReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - loop { - let err = match self.cur_reader { - Some(ref mut r) => { - match r.read(buf) { - Ok(len) => return Ok(len), - Err(ref e) if e.kind == old_io::EndOfFile => None, - Err(e) => Some(e), - } - } - None => break - }; - self.cur_reader = self.readers.next(); - match err { - Some(e) => return Err(e), - None => {} - } - } - Err(old_io::standard_error(old_io::EndOfFile)) - } -} - -/// A `Reader` which forwards input from another `Reader`, passing it along to -/// a `Writer` as well. Similar to the `tee(1)` command. -#[derive(Debug)] -#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")] -#[unstable(feature = "old_io")] -pub struct TeeReader { - reader: R, - writer: W, -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")] -#[unstable(feature = "old_io")] -impl TeeReader { - /// Creates a new `TeeReader` - #[deprecated(since = "1.0.0", reason = "use std::io's tee method instead")] - #[unstable(feature = "old_io")] - pub fn new(r: R, w: W) -> TeeReader { - TeeReader { reader: r, writer: w } - } - - /// Consumes the `TeeReader`, returning the underlying `Reader` and - /// `Writer`. - pub fn into_inner(self) -> (R, W) { - let TeeReader { reader, writer } = self; - (reader, writer) - } -} - -#[deprecated(since = "1.0.0", reason = "use std::io::Tee instead")] -#[unstable(feature = "old_io")] -impl Reader for TeeReader { - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - self.reader.read(buf).and_then(|len| { - self.writer.write_all(&mut buf[..len]).map(|()| len) - }) - } -} - -/// Copies all data from a `Reader` to a `Writer`. -#[deprecated(since = "1.0.0", reason = "use std::io's copy function instead")] -#[unstable(feature = "old_io")] -pub fn copy(r: &mut R, w: &mut W) -> old_io::IoResult<()> { - let mut buf = [0; super::DEFAULT_BUF_SIZE]; - loop { - let len = match r.read(&mut buf) { - Ok(len) => len, - Err(ref e) if e.kind == old_io::EndOfFile => return Ok(()), - Err(e) => return Err(e), - }; - try!(w.write_all(&buf[..len])); - } -} - -/// An adaptor converting an `Iterator` to a `Reader`. -#[derive(Clone, Debug)] -pub struct IterReader { - iter: T, -} - -impl> IterReader { - /// Creates a new `IterReader` which will read from the specified - /// `Iterator`. - pub fn new(iter: T) -> IterReader { - IterReader { iter: iter } - } -} - -impl> Reader for IterReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> old_io::IoResult { - let mut len = 0; - for (slot, elt) in buf.iter_mut().zip(self.iter.by_ref()) { - *slot = elt; - len += 1; - } - if len == 0 && buf.len() != 0 { - Err(old_io::standard_error(old_io::EndOfFile)) - } else { - Ok(len) - } - } -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - - use old_io::{MemReader, ByRefReader, Reader, Writer, Buffer}; - use old_io; - use super::*; - - #[test] - fn test_limit_reader_unlimited() { - let mut r = MemReader::new(vec!(0, 1, 2)); - { - let mut r = LimitReader::new(r.by_ref(), 4); - assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]); - } - } - - #[test] - fn test_limit_reader_limited() { - let mut r = MemReader::new(vec!(0, 1, 2)); - { - let mut r = LimitReader::new(r.by_ref(), 2); - assert_eq!(r.read_to_end().unwrap(), [0, 1]); - } - assert_eq!(r.read_to_end().unwrap(), [2]); - } - - #[test] - fn test_limit_reader_limit() { - let r = MemReader::new(vec!(0, 1, 2)); - let mut r = LimitReader::new(r, 3); - assert_eq!(3, r.limit()); - assert_eq!(0, r.read_byte().unwrap()); - assert_eq!(2, r.limit()); - assert_eq!(r.read_to_end().unwrap(), [1, 2]); - assert_eq!(0, r.limit()); - } - - #[test] - fn test_limit_reader_overlong_consume() { - let mut r = MemReader::new(vec![0, 1, 2, 3, 4, 5]); - let mut r = LimitReader::new(r.by_ref(), 1); - r.consume(2); - assert_eq!(r.read_to_end().unwrap(), []); - } - - #[test] - fn test_null_writer() { - let mut s = NullWriter; - let buf = vec![0, 0, 0]; - s.write_all(&buf).unwrap(); - s.flush().unwrap(); - } - - #[test] - fn test_zero_reader() { - let mut s = ZeroReader; - let mut buf = vec![1, 2, 3]; - assert_eq!(s.read(&mut buf), Ok(3)); - assert_eq!(buf, [0, 0, 0]); - } - - #[test] - fn test_null_reader() { - let mut r = NullReader; - let mut buf = vec![0]; - assert!(r.read(&mut buf).is_err()); - } - - #[test] - fn test_multi_writer() { - static mut writes: usize = 0; - static mut flushes: usize = 0; - - struct TestWriter; - impl Writer for TestWriter { - fn write_all(&mut self, _buf: &[u8]) -> old_io::IoResult<()> { - unsafe { writes += 1 } - Ok(()) - } - - fn flush(&mut self) -> old_io::IoResult<()> { - unsafe { flushes += 1 } - Ok(()) - } - } - - let mut multi = MultiWriter::new(vec!(box TestWriter as Box, - box TestWriter as Box)); - multi.write_all(&[1, 2, 3]).unwrap(); - assert_eq!(2, unsafe { writes }); - assert_eq!(0, unsafe { flushes }); - multi.flush().unwrap(); - assert_eq!(2, unsafe { writes }); - assert_eq!(2, unsafe { flushes }); - } - - #[test] - fn test_chained_reader() { - let rs = vec!(MemReader::new(vec!(0, 1)), MemReader::new(vec!()), - MemReader::new(vec!(2, 3))); - let mut r = ChainedReader::new(rs.into_iter()); - assert_eq!(r.read_to_end().unwrap(), [0, 1, 2, 3]); - } - - #[test] - fn test_tee_reader() { - let mut r = TeeReader::new(MemReader::new(vec!(0, 1, 2)), - Vec::new()); - assert_eq!(r.read_to_end().unwrap(), [0, 1, 2]); - let (_, w) = r.into_inner(); - assert_eq!(w, [0, 1, 2]); - } - - #[test] - fn test_copy() { - let mut r = MemReader::new(vec!(0, 1, 2, 3, 4)); - let mut w = Vec::new(); - copy(&mut r, &mut w).unwrap(); - assert_eq!(w, [0, 1, 2, 3, 4]); - } - - #[test] - fn limit_reader_buffer() { - let mut r: &[u8] = b"0123456789\n0123456789\n"; - let r = &mut r; - { - let mut r = LimitReader::new(r.by_ref(), 3); - assert_eq!(r.read_line(), Ok("012".to_string())); - assert_eq!(r.limit(), 0); - assert_eq!(r.read_line().err().unwrap().kind, old_io::EndOfFile); - } - { - let mut r = LimitReader::new(r.by_ref(), 9); - assert_eq!(r.read_line(), Ok("3456789\n".to_string())); - assert_eq!(r.limit(), 1); - assert_eq!(r.read_line(), Ok("0".to_string())); - } - { - let mut r = LimitReader::new(r.by_ref(), 100); - assert_eq!(r.read_char(), Ok('1')); - assert_eq!(r.limit(), 99); - assert_eq!(r.read_line(), Ok("23456789\n".to_string())); - } - } - - #[test] - fn test_iter_reader() { - let mut r = IterReader::new(0..8); - let mut buf = [0, 0, 0]; - let len = r.read(&mut buf).unwrap(); - assert_eq!(len, 3); - assert!(buf == [0, 1, 2]); - - let len = r.read(&mut buf).unwrap(); - assert_eq!(len, 3); - assert!(buf == [3, 4, 5]); - - let len = r.read(&mut buf).unwrap(); - assert_eq!(len, 2); - assert!(buf == [6, 7, 5]); - - assert_eq!(r.read(&mut buf).unwrap_err().kind, old_io::EndOfFile); - } - - #[test] - fn iter_reader_zero_length() { - let mut r = IterReader::new(0..8); - let mut buf = []; - assert_eq!(Ok(0), r.read(&mut buf)); - } -} diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs deleted file mode 100644 index 9c88533d3b..0000000000 --- a/src/libstd/old_path/mod.rs +++ /dev/null @@ -1,989 +0,0 @@ -// Copyright 2013 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. - -//! Cross-platform path support -//! -//! This module implements support for two flavors of paths. `PosixPath` represents a path on any -//! unix-like system, whereas `WindowsPath` represents a path on Windows. This module also exposes -//! a typedef `Path` which is equal to the appropriate platform-specific path variant. -//! -//! Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which contains the set of -//! methods that behave the same for both paths. They each also implement some methods that could -//! not be expressed in `GenericPath`, yet behave identically for both path flavors, such as -//! `.components()`. -//! -//! The three main design goals of this module are 1) to avoid unnecessary allocation, 2) to behave -//! the same regardless of which flavor of path is being used, and 3) to support paths that cannot -//! be represented in UTF-8 (as Linux has no restriction on paths beyond disallowing NUL). -//! -//! ## Usage -//! -//! Usage of this module is fairly straightforward. Unless writing platform-specific code, `Path` -//! should be used to refer to the platform-native path. -//! -//! Creation of a path is typically done with either `Path::new(some_str)` or -//! `Path::new(some_vec)`. This path can be modified with `.push()` and `.pop()` (and other -//! setters). The resulting Path can either be passed to another API that expects a path, or can be -//! turned into a `&[u8]` with `.as_vec()` or a `Option<&str>` with `.as_str()`. Similarly, -//! attributes of the path can be queried with methods such as `.filename()`. There are also -//! methods that return a new path instead of modifying the receiver, such as `.join()` or -//! `.dir_path()`. -//! -//! Paths are always kept in normalized form. This means that creating the path -//! `Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt to mutate the path -//! will always leave it in normalized form. -//! -//! When rendering a path to some form of output, there is a method `.display()` which is -//! compatible with the `format!()` parameter `{}`. This will render the path as a string, -//! replacing all non-utf8 sequences with the Replacement Character (U+FFFD). As such it is not -//! suitable for passing to any API that actually operates on the path; it is only intended for -//! display. -//! -//! ## Examples -//! -//! ```rust -//! # #![feature(old_path, old_io)] -//! use std::old_io::fs::PathExtensions; -//! use std::old_path::{Path, GenericPath}; -//! -//! let mut path = Path::new("/tmp/path"); -//! println!("path: {}", path.display()); -//! path.set_filename("foo"); -//! path.push("bar"); -//! println!("new path: {}", path.display()); -//! println!("path exists: {}", path.exists()); -//! ``` - -#![unstable(feature = "old_path")] -#![deprecated(since = "1.0.0", reason = "use std::path instead")] -#![allow(deprecated)] // seriously this is all deprecated -#![allow(unused_imports)] - -use core::marker::Sized; -use ffi::CString; -use clone::Clone; -use borrow::Cow; -use fmt; -use iter::Iterator; -use option::Option; -use option::Option::{None, Some}; -use str; -use string::String; -use vec::Vec; - -/// Typedef for POSIX file paths. -/// See `posix::Path` for more info. -pub use self::posix::Path as PosixPath; - -/// Typedef for Windows file paths. -/// See `windows::Path` for more info. -pub use self::windows::Path as WindowsPath; - -/// Typedef for the platform-native path type -#[cfg(unix)] -pub use self::posix::Path as Path; -/// Typedef for the platform-native path type -#[cfg(windows)] -pub use self::windows::Path as Path; - -/// Typedef for the platform-native component iterator -#[cfg(unix)] -pub use self::posix::Components as Components; -/// Typedef for the platform-native component iterator -#[cfg(windows)] -pub use self::windows::Components as Components; - -/// Typedef for the platform-native str component iterator -#[cfg(unix)] -pub use self::posix::StrComponents as StrComponents; -/// Typedef for the platform-native str component iterator -#[cfg(windows)] -pub use self::windows::StrComponents as StrComponents; - -/// Alias for the platform-native separator character. -#[cfg(unix)] -pub use self::posix::SEP as SEP; -/// Alias for the platform-native separator character. -#[cfg(windows)] -pub use self::windows::SEP as SEP; - -/// Alias for the platform-native separator byte. -#[cfg(unix)] -pub use self::posix::SEP_BYTE as SEP_BYTE; -/// Alias for the platform-native separator byte. -#[cfg(windows)] -pub use self::windows::SEP_BYTE as SEP_BYTE; - -/// Typedef for the platform-native separator char func -#[cfg(unix)] -pub use self::posix::is_sep as is_sep; -/// Typedef for the platform-native separator char func -#[cfg(windows)] -pub use self::windows::is_sep as is_sep; -/// Typedef for the platform-native separator byte func -#[cfg(unix)] -pub use self::posix::is_sep_byte as is_sep_byte; -/// Typedef for the platform-native separator byte func -#[cfg(windows)] -pub use self::windows::is_sep_byte as is_sep_byte; - -pub mod posix; -pub mod windows; - -/// A trait that represents the generic operations available on paths -pub trait GenericPath: Clone + GenericPathUnsafe { - /// Creates a new Path from a byte vector or string. - /// The resulting Path will always be normalized. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let path = Path::new("foo/bar"); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - /// - /// See individual Path impls for additional restrictions. - #[inline] - fn new(path: T) -> Self { - assert!(!contains_nul(&path)); - unsafe { GenericPathUnsafe::new_unchecked(path) } - } - - /// Creates a new Path from a byte vector or string, if possible. - /// The resulting Path will always be normalized. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let x: &[u8] = b"foo\0"; - /// assert!(Path::new_opt(x).is_none()); - /// # } - /// ``` - #[inline] - fn new_opt(path: T) -> Option { - if contains_nul(&path) { - None - } else { - Some(unsafe { GenericPathUnsafe::new_unchecked(path) }) - } - } - - /// Returns the path as a string, if possible. - /// If the path is not representable in utf-8, this returns None. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def"); - /// assert_eq!(p.as_str(), Some("/abc/def")); - /// # } - /// ``` - #[inline] - fn as_str<'a>(&'a self) -> Option<&'a str> { - str::from_utf8(self.as_vec()).ok() - } - - /// Returns the path as a byte vector - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert_eq!(p.as_vec(), b"abc/def"); - /// # } - /// ``` - fn as_vec<'a>(&'a self) -> &'a [u8]; - - /// Converts the Path into an owned byte vector - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert_eq!(p.into_vec(), b"abc/def".to_vec()); - /// // attempting to use p now results in "error: use of moved value" - /// # } - /// ``` - fn into_vec(self) -> Vec; - - /// Returns an object that implements `Display` for printing paths - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// println!("{}", p.display()); // prints "abc/def" - /// # } - /// ``` - fn display<'a>(&'a self) -> Display<'a, Self> { - Display{ path: self, filename: false } - } - - /// Returns an object that implements `Display` for printing filenames - /// - /// If there is no filename, nothing will be printed. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// println!("{}", p.filename_display()); // prints "def" - /// # } - /// ``` - fn filename_display<'a>(&'a self) -> Display<'a, Self> { - Display{ path: self, filename: true } - } - - /// Returns the directory component of `self`, as a byte vector (with no trailing separator). - /// If `self` has no directory component, returns ['.']. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.dirname(), b"abc/def"); - /// # } - /// ``` - fn dirname<'a>(&'a self) -> &'a [u8]; - - /// Returns the directory component of `self`, as a string, if possible. - /// See `dirname` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.dirname_str(), Some("abc/def")); - /// # } - /// ``` - #[inline] - fn dirname_str<'a>(&'a self) -> Option<&'a str> { - str::from_utf8(self.dirname()).ok() - } - - /// Returns the file component of `self`, as a byte vector. - /// If `self` represents the root of the file hierarchy, returns None. - /// If `self` is "." or "..", returns None. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.filename(), Some(&b"ghi"[..])); - /// # } - /// ``` - fn filename<'a>(&'a self) -> Option<&'a [u8]>; - - /// Returns the file component of `self`, as a string, if possible. - /// See `filename` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.filename_str(), Some("ghi")); - /// # } - /// ``` - #[inline] - fn filename_str<'a>(&'a self) -> Option<&'a str> { - self.filename().and_then(|s| str::from_utf8(s).ok()) - } - - /// Returns the stem of the filename of `self`, as a byte vector. - /// The stem is the portion of the filename just before the last '.'. - /// If there is no '.', the entire filename is returned. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def.txt"); - /// assert_eq!(p.filestem(), Some(&b"def"[..])); - /// # } - /// ``` - fn filestem<'a>(&'a self) -> Option<&'a [u8]> { - match self.filename() { - None => None, - Some(name) => Some({ - let dot = b'.'; - match name.rposition_elem(&dot) { - None | Some(0) => name, - Some(1) if name == b".." => name, - Some(pos) => &name[..pos] - } - }) - } - } - - /// Returns the stem of the filename of `self`, as a string, if possible. - /// See `filestem` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def.txt"); - /// assert_eq!(p.filestem_str(), Some("def")); - /// # } - /// ``` - #[inline] - fn filestem_str<'a>(&'a self) -> Option<&'a str> { - self.filestem().and_then(|s| str::from_utf8(s).ok()) - } - - /// Returns the extension of the filename of `self`, as an optional byte vector. - /// The extension is the portion of the filename just after the last '.'. - /// If there is no extension, None is returned. - /// If the filename ends in '.', the empty vector is returned. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def.txt"); - /// assert_eq!(p.extension(), Some(&b"txt"[..])); - /// # } - /// ``` - fn extension<'a>(&'a self) -> Option<&'a [u8]> { - match self.filename() { - None => None, - Some(name) => { - let dot = b'.'; - match name.rposition_elem(&dot) { - None | Some(0) => None, - Some(1) if name == b".." => None, - Some(pos) => Some(&name[pos+1..]) - } - } - } - } - - /// Returns the extension of the filename of `self`, as a string, if possible. - /// See `extension` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def.txt"); - /// assert_eq!(p.extension_str(), Some("txt")); - /// # } - /// ``` - #[inline] - fn extension_str<'a>(&'a self) -> Option<&'a str> { - self.extension().and_then(|s| str::from_utf8(s).ok()) - } - - /// Replaces the filename portion of the path with the given byte vector or string. - /// If the replacement name is [], this is equivalent to popping the path. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// p.set_filename("foo.dat"); - /// assert!(p == Path::new("abc/foo.dat")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the filename contains a NUL. - #[inline] - fn set_filename(&mut self, filename: T) { - assert!(!contains_nul(&filename)); - unsafe { self.set_filename_unchecked(filename) } - } - - /// Replaces the extension with the given byte vector or string. - /// If there is no extension in `self`, this adds one. - /// If the argument is [] or "", this removes the extension. - /// If `self` has no filename, this is a no-op. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// p.set_extension("csv"); - /// assert_eq!(p, Path::new("abc/def.csv")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the extension contains a NUL. - fn set_extension(&mut self, extension: T) { - assert!(!contains_nul(&extension)); - - let val = self.filename().and_then(|name| { - let dot = b'.'; - let extlen = extension.container_as_bytes().len(); - match (name.rposition_elem(&dot), extlen) { - (None, 0) | (Some(0), 0) => None, - (Some(idx), 0) => Some(name[..idx].to_vec()), - (idx, extlen) => { - let idx = match idx { - None | Some(0) => name.len(), - Some(val) => val - }; - - let mut v; - v = Vec::with_capacity(idx + extlen + 1); - v.push_all(&name[..idx]); - v.push(dot); - v.push_all(extension.container_as_bytes()); - Some(v) - } - } - }); - - match val { - None => (), - Some(v) => unsafe { self.set_filename_unchecked(v) } - } - } - - /// Returns a new Path constructed by replacing the filename with the given - /// byte vector or string. - /// See `set_filename` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// assert_eq!(p.with_filename("foo.dat"), Path::new("abc/foo.dat")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the filename contains a NUL. - #[inline] - fn with_filename(&self, filename: T) -> Self { - let mut p = self.clone(); - p.set_filename(filename); - p - } - - /// Returns a new Path constructed by setting the extension to the given - /// byte vector or string. - /// See `set_extension` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// assert_eq!(p.with_extension("csv"), Path::new("abc/def.csv")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the extension contains a NUL. - #[inline] - fn with_extension(&self, extension: T) -> Self { - let mut p = self.clone(); - p.set_extension(extension); - p - } - - /// Returns the directory component of `self`, as a Path. - /// If `self` represents the root of the filesystem hierarchy, returns `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.dir_path(), Path::new("abc/def")); - /// # } - /// ``` - fn dir_path(&self) -> Self { - // self.dirname() returns a NUL-free vector - unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) } - } - - /// Returns a Path that represents the filesystem root that `self` is rooted in. - /// - /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// assert_eq!(Path::new("abc/def").root_path(), None); - /// assert_eq!(Path::new("/abc/def").root_path(), Some(Path::new("/"))); - /// # } - /// ``` - fn root_path(&self) -> Option; - - /// Pushes a path (as a byte vector or string) onto `self`. - /// If the argument represents an absolute path, it replaces `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo/bar"); - /// p.push("baz.txt"); - /// assert_eq!(p, Path::new("foo/bar/baz.txt")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - #[inline] - fn push(&mut self, path: T) { - assert!(!contains_nul(&path)); - unsafe { self.push_unchecked(path) } - } - - /// Pushes multiple paths (as byte vectors or strings) onto `self`. - /// See `push` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo"); - /// p.push_many(&["bar", "baz.txt"]); - /// assert_eq!(p, Path::new("foo/bar/baz.txt")); - /// # } - /// ``` - #[inline] - fn push_many(&mut self, paths: &[T]) { - let t: Option<&T> = None; - if BytesContainer::is_str(t) { - for p in paths { - self.push(p.container_as_str().unwrap()) - } - } else { - for p in paths { - self.push(p.container_as_bytes()) - } - } - } - - /// Removes the last path component from the receiver. - /// Returns `true` if the receiver was modified, or `false` if it already - /// represented the root of the file hierarchy. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo/bar/baz.txt"); - /// p.pop(); - /// assert_eq!(p, Path::new("foo/bar")); - /// # } - /// ``` - fn pop(&mut self) -> bool; - - /// Returns a new Path constructed by joining `self` with the given path - /// (as a byte vector or string). - /// If the given path is absolute, the new Path will represent just that. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/foo"); - /// assert_eq!(p.join("bar.txt"), Path::new("/foo/bar.txt")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - #[inline] - fn join(&self, path: T) -> Self { - let mut p = self.clone(); - p.push(path); - p - } - - /// Returns a new Path constructed by joining `self` with the given paths - /// (as byte vectors or strings). - /// See `join` for details. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo"); - /// let fbbq = Path::new("foo/bar/baz/quux.txt"); - /// assert_eq!(p.join_many(&["bar", "baz", "quux.txt"]), fbbq); - /// # } - /// ``` - #[inline] - fn join_many(&self, paths: &[T]) -> Self { - let mut p = self.clone(); - p.push_many(paths); - p - } - - /// Returns whether `self` represents an absolute path. - /// An absolute path is defined as one that, when joined to another path, will - /// yield back the same absolute path. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def"); - /// assert!(p.is_absolute()); - /// # } - /// ``` - fn is_absolute(&self) -> bool; - - /// Returns whether `self` represents a relative path. - /// Typically this is the inverse of `is_absolute`. - /// But for Windows paths, it also means the path is not volume-relative or - /// relative to the current working directory. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert!(p.is_relative()); - /// # } - /// ``` - fn is_relative(&self) -> bool { - !self.is_absolute() - } - - /// Returns whether `self` is equal to, or is an ancestor of, the given path. - /// If both paths are relative, they are compared as though they are relative - /// to the same parent path. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let fb = Path::new("foo/bar"); - /// let bq = Path::new("baz/quux.txt"); - /// assert!(fb.is_ancestor_of(&p)); - /// # } - /// ``` - fn is_ancestor_of(&self, other: &Self) -> bool; - - /// Returns the Path that, were it joined to `base`, would yield `self`. - /// If no such path exists, None is returned. - /// If `self` is absolute and `base` is relative, or on Windows if both - /// paths refer to separate drives, an absolute path is returned. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let fb = Path::new("foo/bar"); - /// let bq = Path::new("baz/quux.txt"); - /// assert_eq!(p.path_relative_from(&fb), Some(bq)); - /// # } - /// ``` - fn path_relative_from(&self, base: &Self) -> Option; - - /// Returns whether the relative path `child` is a suffix of `self`. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let bq = Path::new("baz/quux.txt"); - /// assert!(p.ends_with_path(&bq)); - /// # } - /// ``` - fn ends_with_path(&self, child: &Self) -> bool; -} - -/// A trait that represents something bytes-like (e.g. a &[u8] or a &str) -pub trait BytesContainer { - /// Returns a &[u8] representing the receiver - fn container_as_bytes<'a>(&'a self) -> &'a [u8]; - /// Returns the receiver interpreted as a utf-8 string, if possible - #[inline] - fn container_as_str<'a>(&'a self) -> Option<&'a str> { - str::from_utf8(self.container_as_bytes()).ok() - } - /// Returns whether .container_as_str() is guaranteed to not fail - // FIXME (#8888): Remove unused arg once :: works - #[inline] - fn is_str(_: Option<&Self>) -> bool { false } -} - -/// A trait that represents the unsafe operations on GenericPaths -pub trait GenericPathUnsafe { - /// Creates a new Path without checking for null bytes. - /// The resulting Path will always be normalized. - unsafe fn new_unchecked(path: T) -> Self; - - /// Replaces the filename portion of the path without checking for null - /// bytes. - /// See `set_filename` for details. - unsafe fn set_filename_unchecked(&mut self, filename: T); - - /// Pushes a path onto `self` without checking for null bytes. - /// See `push` for details. - unsafe fn push_unchecked(&mut self, path: T); -} - -/// Helper struct for printing paths with format!() -pub struct Display<'a, P:'a> { - path: &'a P, - filename: bool -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: GenericPath> fmt::Debug for Display<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.as_cow(), f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, P: GenericPath> fmt::Display for Display<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_cow().fmt(f) - } -} - -impl<'a, P: GenericPath> Display<'a, P> { - /// Returns the path as a possibly-owned string. - /// - /// If the path is not UTF-8, invalid sequences will be replaced with the - /// Unicode replacement char. This involves allocation. - #[inline] - pub fn as_cow(&self) -> Cow<'a, str> { - String::from_utf8_lossy(if self.filename { - match self.path.filename() { - None => { - let result: &[u8] = &[]; - result - } - Some(v) => v - } - } else { - self.path.as_vec() - }) - } -} - -impl BytesContainer for str { - #[inline] - fn container_as_bytes(&self) -> &[u8] { - self.as_bytes() - } - #[inline] - fn container_as_str(&self) -> Option<&str> { - Some(self) - } - #[inline] - fn is_str(_: Option<&str>) -> bool { true } -} - -impl BytesContainer for String { - #[inline] - fn container_as_bytes(&self) -> &[u8] { - self.as_bytes() - } - #[inline] - fn container_as_str(&self) -> Option<&str> { - Some(&self[..]) - } - #[inline] - fn is_str(_: Option<&String>) -> bool { true } -} - -impl BytesContainer for [u8] { - #[inline] - fn container_as_bytes(&self) -> &[u8] { - self - } -} - -impl BytesContainer for Vec { - #[inline] - fn container_as_bytes(&self) -> &[u8] { - &self[..] - } -} - -impl BytesContainer for CString { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_bytes() - } -} - -impl<'a, T: ?Sized + BytesContainer> BytesContainer for &'a T { - #[inline] - fn container_as_bytes(&self) -> &[u8] { - (**self).container_as_bytes() - } - #[inline] - fn container_as_str(&self) -> Option<&str> { - (**self).container_as_str() - } - #[inline] - fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) } -} - -#[inline(always)] -fn contains_nul(v: &T) -> bool { - v.container_as_bytes().iter().any(|&x| x == 0) -} diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs deleted file mode 100644 index c517fab257..0000000000 --- a/src/libstd/old_path/posix.rs +++ /dev/null @@ -1,1348 +0,0 @@ -// Copyright 2013-2014 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. - -//! POSIX file path handling - -use clone::Clone; -use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; -use fmt; -use hash; -use old_io::Writer; -use iter::{AdditiveIterator, Extend}; -use iter::{Iterator, Map}; -use marker::Sized; -use option::Option::{self, Some, None}; -use result::Result::{self, Ok, Err}; -use slice::{Split, SliceConcatExt}; -use str::{self, FromStr}; -use vec::Vec; - -use super::{BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = Split<'a, u8, fn(&u8) -> bool>; - -/// Iterator that yields successive components of a Path as Option<&str> -pub type StrComponents<'a> = - Map, fn(&[u8]) -> Option<&str>>; - -/// Represents a POSIX file path -#[derive(Clone)] -pub struct Path { - repr: Vec, // assumed to never be empty or contain NULs - sepidx: Option // index of the final separator in repr -} - -/// The standard path separator character -pub const SEP: char = '/'; - -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// Returns whether the given byte is a path separator -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { - *u as char == SEP -} - -/// Returns whether the given char is a path separator -#[inline] -pub fn is_sep(c: char) -> bool { - c == SEP -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.display(), f) - } -} - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.repr == other.repr - } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { - self.repr.cmp(&other.repr) - } -} - -impl FromStr for Path { - type Err = ParsePathError; - fn from_str(s: &str) -> Result { - match Path::new_opt(s) { - Some(p) => Ok(p), - None => Err(ParsePathError), - } - } -} - -/// Valuelue indicating that a path could not be parsed from a string. -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParsePathError; - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Path { - #[inline] - fn hash(&self, state: &mut H) { - self.repr.hash(state) - } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_vec() - } -} - -impl GenericPathUnsafe for Path { - unsafe fn new_unchecked(path: T) -> Path { - let path = Path::normalize(path.container_as_bytes()); - assert!(!path.is_empty()); - let idx = path.rposition_elem(&SEP_BYTE); - Path{ repr: path, sepidx: idx } - } - - unsafe fn set_filename_unchecked(&mut self, filename: T) { - let filename = filename.container_as_bytes(); - match self.sepidx { - None if self.repr == b".." => { - let mut v = Vec::with_capacity(3 + filename.len()); - v.push_all(dot_dot_static); - v.push(SEP_BYTE); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - None => { - self.repr = Path::normalize(filename); - } - Some(idx) if &self.repr[idx+1..] == b".." => { - let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len()); - v.push_all(&self.repr); - v.push(SEP_BYTE); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - Some(idx) => { - let mut v = Vec::with_capacity(idx + 1 + filename.len()); - v.push_all(&self.repr[..idx+1]); - v.push_all(filename); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - } - - unsafe fn push_unchecked(&mut self, path: T) { - let path = path.container_as_bytes(); - if !path.is_empty() { - if path[0] == SEP_BYTE { - self.repr = Path::normalize(path); - } else { - let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1); - v.push_all(&self.repr); - v.push(SEP_BYTE); - v.push_all(path); - // FIXME: this is slow - self.repr = Path::normalize(&v); - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - } - } -} - -impl GenericPath for Path { - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { - &self.repr - } - - fn into_vec(self) -> Vec { - self.repr - } - - fn dirname<'a>(&'a self) -> &'a [u8] { - match self.sepidx { - None if self.repr == b".." => &self.repr, - None => dot_static, - Some(0) => &self.repr[..1], - Some(idx) if &self.repr[idx+1..] == b".." => &self.repr, - Some(idx) => &self.repr[..idx] - } - } - - fn filename<'a>(&'a self) -> Option<&'a [u8]> { - match self.sepidx { - None if self.repr == b"." || self.repr == b".." => None, - None => Some(&self.repr), - Some(idx) if &self.repr[idx+1..] == b".." => None, - Some(0) if self.repr[1..].is_empty() => None, - Some(idx) => Some(&self.repr[idx+1..]) - } - } - - fn pop(&mut self) -> bool { - match self.sepidx { - None if self.repr == b"." => false, - None => { - self.repr = vec![b'.']; - self.sepidx = None; - true - } - Some(0) if self.repr == b"/" => false, - Some(idx) => { - if idx == 0 { - self.repr.truncate(idx+1); - } else { - self.repr.truncate(idx); - } - self.sepidx = self.repr.rposition_elem(&SEP_BYTE); - true - } - } - } - - fn root_path(&self) -> Option { - if self.is_absolute() { - Some(Path::new("/")) - } else { - None - } - } - - #[inline] - fn is_absolute(&self) -> bool { - self.repr[0] == SEP_BYTE - } - - fn is_ancestor_of(&self, other: &Path) -> bool { - if self.is_absolute() != other.is_absolute() { - false - } else { - let mut ita = self.components(); - let mut itb = other.components(); - if self.repr == b"." { - return match itb.next() { - None => true, - Some(b) => b != b".." - }; - } - loop { - match (ita.next(), itb.next()) { - (None, _) => break, - (Some(a), Some(b)) if a == b => { continue }, - (Some(a), _) if a == b".." => { - // if ita contains only .. components, it's an ancestor - return ita.all(|x| x == b".."); - } - _ => return false - } - } - true - } - } - - fn path_relative_from(&self, base: &Path) -> Option { - if self.is_absolute() != base.is_absolute() { - if self.is_absolute() { - Some(self.clone()) - } else { - None - } - } else { - let mut ita = self.components(); - let mut itb = base.components(); - let mut comps = vec![]; - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) => { - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - (None, _) => comps.push(dot_dot_static), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if b == b"." => comps.push(a), - (Some(_), Some(b)) if b == b".." => return None, - (Some(a), Some(_)) => { - comps.push(dot_dot_static); - for _ in itb { - comps.push(dot_dot_static); - } - comps.push(a); - comps.extend(ita.by_ref()); - break; - } - } - } - Some(Path::new(comps.connect(&SEP_BYTE))) - } - } - - fn ends_with_path(&self, child: &Path) -> bool { - if !child.is_relative() { return false; } - let mut selfit = self.components().rev(); - let mut childit = child.components().rev(); - loop { - match (selfit.next(), childit.next()) { - (Some(a), Some(b)) => if a != b { return false; }, - (Some(_), None) => break, - (None, Some(_)) => return false, - (None, None) => break - } - } - true - } -} - -impl Path { - /// Returns a new Path from a byte vector or string - /// - /// # Panics - /// - /// Panics the task if the vector contains a NUL. - #[inline] - pub fn new(path: T) -> Path { - GenericPath::new(path) - } - - /// Returns a new Path from a byte vector or string, if possible - #[inline] - pub fn new_opt(path: T) -> Option { - GenericPath::new_opt(path) - } - - /// Returns a normalized byte vector representation of a path, by removing all empty - /// components, and unnecessary . and .. components. - fn normalize(v: &[u8]) -> Vec { - // borrowck is being very picky - let val = { - let is_abs = !v.is_empty() && v[0] == SEP_BYTE; - let v_ = if is_abs { &v[1..] } else { v }; - let comps = normalize_helper(v_, is_abs); - match comps { - None => None, - Some(comps) => { - if is_abs && comps.is_empty() { - Some(vec![SEP_BYTE]) - } else { - let n = if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum(); - let mut v = Vec::with_capacity(n); - let mut it = comps.into_iter(); - if !is_abs { - match it.next() { - None => (), - Some(comp) => v.push_all(comp) - } - } - for comp in it { - v.push(SEP_BYTE); - v.push_all(comp); - } - Some(v) - } - } - } - }; - match val { - None => v.to_vec(), - Some(val) => val - } - } - - /// Returns an iterator that yields each component of the path in turn. - /// Does not distinguish between absolute and relative paths, e.g. - /// /a/b/c and a/b/c yield the same set of components. - /// A path of "/" yields no components. A path of "." yields one component. - pub fn components<'a>(&'a self) -> Components<'a> { - let v = if self.repr[0] == SEP_BYTE { - &self.repr[1..] - } else { &*self.repr }; - let is_sep_byte: fn(&u8) -> bool = is_sep_byte; // coerce to fn ptr - let mut ret = v.split(is_sep_byte); - if v.is_empty() { - // consume the empty "" component - ret.next(); - } - ret - } - - /// Returns an iterator that yields each component of the path as Option<&str>. - /// See components() for details. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { - fn from_utf8(s: &[u8]) -> Option<&str> { - str::from_utf8(s).ok() - } - let f: fn(&[u8]) -> Option<&str> = from_utf8; // coerce to fn ptr - self.components().map(f) - } -} - -// None result means the byte vector didn't need normalizing -fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { - if is_abs && v.is_empty() { - return None; - } - let mut comps: Vec<&'a [u8]> = vec![]; - let mut n_up = 0; - let mut changed = false; - for comp in v.split(is_sep_byte) { - if comp.is_empty() { changed = true } - else if comp == b"." { changed = true } - else if comp == b".." { - if is_abs && comps.is_empty() { changed = true } - else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 } - else { comps.pop().unwrap(); changed = true } - } else { comps.push(comp) } - } - if changed { - if comps.is_empty() && !is_abs { - if v == b"." { - return None; - } - comps.push(dot_static); - } - Some(comps) - } else { - None - } -} - -#[allow(non_upper_case_globals)] -static dot_static: &'static [u8] = b"."; -#[allow(non_upper_case_globals)] -static dot_dot_static: &'static [u8] = b".."; - -#[cfg(test)] -mod tests { - use super::*; - - use clone::Clone; - use option::Option::{self, Some, None}; - use old_path::GenericPath; - use str; - use string::ToString; - use vec::Vec; - use iter::Iterator; - - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_str(), Some($exp)); - } - ); - (v: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_vec(), $exp); - } - ) - } - - #[test] - fn test_paths() { - let empty: &[u8] = &[]; - t!(v: Path::new(empty), b"."); - t!(v: Path::new(&b"/"[..]), b"/"); - t!(v: Path::new(&b"a/b/c"[..]), b"a/b/c"); - t!(v: Path::new(&b"a/b/c\xFF"[..]), b"a/b/c\xFF"); - t!(v: Path::new(&b"\xFF/../foo\x80"[..]), b"foo\x80"); - let p = Path::new(&b"a/b/c\xFF"[..]); - assert!(p.as_str().is_none()); - - t!(s: Path::new(""), "."); - t!(s: Path::new("/"), "/"); - t!(s: Path::new("hi"), "hi"); - t!(s: Path::new("hi/"), "hi"); - t!(s: Path::new("/lib"), "/lib"); - t!(s: Path::new("/lib/"), "/lib"); - t!(s: Path::new("hi/there"), "hi/there"); - t!(s: Path::new("hi/there.txt"), "hi/there.txt"); - - t!(s: Path::new("hi/there/"), "hi/there"); - t!(s: Path::new("hi/../there"), "there"); - t!(s: Path::new("../hi/there"), "../hi/there"); - t!(s: Path::new("/../hi/there"), "/hi/there"); - t!(s: Path::new("foo/.."), "."); - t!(s: Path::new("/foo/.."), "/"); - t!(s: Path::new("/foo/../.."), "/"); - t!(s: Path::new("/foo/../../bar"), "/bar"); - t!(s: Path::new("/./hi/./there/."), "/hi/there"); - t!(s: Path::new("/./hi/./there/./.."), "/hi"); - t!(s: Path::new("foo/../.."), ".."); - t!(s: Path::new("foo/../../.."), "../.."); - t!(s: Path::new("foo/../../bar"), "../bar"); - - assert_eq!(Path::new(&b"foo/bar"[..]).into_vec(), b"foo/bar"); - assert_eq!(Path::new(&b"/foo/../../bar"[..]).into_vec(), - b"/bar"); - - let p = Path::new(&b"foo/bar\x80"[..]); - assert!(p.as_str().is_none()); - } - - #[test] - fn test_opt_paths() { - assert!(Path::new_opt(&b"foo/bar\0"[..]).is_none()); - t!(v: Path::new_opt(&b"foo/bar"[..]).unwrap(), b"foo/bar"); - assert!(Path::new_opt("foo/bar\0").is_none()); - t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar"); - } - - #[test] - fn test_null_byte() { - use thread; - let result = thread::spawn(move|| { - Path::new(&b"foo/bar\0"[..]); - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").set_filename(&b"f\0o"[..]) - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").push(&b"f\0o"[..]); - }).join(); - assert!(result.is_err()); - } - - #[test] - fn test_display_str() { - macro_rules! t { - ($path:expr, $disp:ident, $exp:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.$disp().to_string(), $exp); - } - ) - } - t!("foo", display, "foo"); - t!(&b"foo\x80"[..], display, "foo\u{FFFD}"); - t!(&b"foo\xFFbar"[..], display, "foo\u{FFFD}bar"); - t!(&b"foo\xFF/bar"[..], filename_display, "bar"); - t!(&b"foo/\xFFbar"[..], filename_display, "\u{FFFD}bar"); - t!(&b"/"[..], filename_display, ""); - - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let mo = path.display().as_cow(); - assert_eq!(mo, $exp); - } - ); - ($path:expr, $exp:expr, filename) => ( - { - let path = Path::new($path); - let mo = path.filename_display().as_cow(); - assert_eq!(mo, $exp); - } - ) - } - - t!("foo", "foo"); - t!(&b"foo\x80"[..], "foo\u{FFFD}"); - t!(&b"foo\xFFbar"[..], "foo\u{FFFD}bar"); - t!(&b"foo\xFF/bar"[..], "bar", filename); - t!(&b"foo/\xFFbar"[..], "\u{FFFD}bar", filename); - t!(&b"/"[..], "", filename); - } - - #[test] - fn test_display() { - macro_rules! t { - ($path:expr, $exp:expr, $expf:expr) => ( - { - let path = Path::new($path); - let f = format!("{}", path.display()); - assert_eq!(f, $exp); - let f = format!("{}", path.filename_display()); - assert_eq!(f, $expf); - } - ) - } - - t!(&b"foo"[..], "foo", "foo"); - t!(&b"foo/bar"[..], "foo/bar", "bar"); - t!(&b"/"[..], "/", ""); - t!(&b"foo\xFF"[..], "foo\u{FFFD}", "foo\u{FFFD}"); - t!(&b"foo\xFF/bar"[..], "foo\u{FFFD}/bar", "bar"); - t!(&b"foo/\xFFbar"[..], "foo/\u{FFFD}bar", "\u{FFFD}bar"); - t!(&b"\xFFfoo/bar\xFF"[..], "\u{FFFD}foo/bar\u{FFFD}", "bar\u{FFFD}"); - } - - #[test] - fn test_components() { - macro_rules! t { - (s: $path:expr, $op:ident, $exp:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.$op(), ($exp).as_bytes()); - } - ); - (s: $path:expr, $op:ident, $exp:expr, opt) => ( - { - let path = Path::new($path); - let left = path.$op().map(|x| str::from_utf8(x).unwrap()); - assert_eq!(left, $exp); - } - ); - (v: $path:expr, $op:ident, $exp:expr) => ( - { - let arg = $path; - let path = Path::new(arg); - assert_eq!(path.$op(), $exp); - } - ); - } - - t!(v: &b"a/b/c"[..], filename, Some(&b"c"[..])); - t!(v: &b"a/b/c\xFF"[..], filename, Some(&b"c\xFF"[..])); - t!(v: &b"a/b\xFF/c"[..], filename, Some(&b"c"[..])); - t!(s: "a/b/c", filename, Some("c"), opt); - t!(s: "/a/b/c", filename, Some("c"), opt); - t!(s: "a", filename, Some("a"), opt); - t!(s: "/a", filename, Some("a"), opt); - t!(s: ".", filename, None, opt); - t!(s: "/", filename, None, opt); - t!(s: "..", filename, None, opt); - t!(s: "../..", filename, None, opt); - - t!(v: &b"a/b/c"[..], dirname, b"a/b"); - t!(v: &b"a/b/c\xFF"[..], dirname, b"a/b"); - t!(v: &b"a/b\xFF/c"[..], dirname, b"a/b\xFF"); - t!(s: "a/b/c", dirname, "a/b"); - t!(s: "/a/b/c", dirname, "/a/b"); - t!(s: "a", dirname, "."); - t!(s: "/a", dirname, "/"); - t!(s: ".", dirname, "."); - t!(s: "/", dirname, "/"); - t!(s: "..", dirname, ".."); - t!(s: "../..", dirname, "../.."); - - t!(v: &b"hi/there.txt"[..], filestem, Some(&b"there"[..])); - t!(v: &b"hi/there\x80.txt"[..], filestem, Some(&b"there\x80"[..])); - t!(v: &b"hi/there.t\x80xt"[..], filestem, Some(&b"there"[..])); - t!(s: "hi/there.txt", filestem, Some("there"), opt); - t!(s: "hi/there", filestem, Some("there"), opt); - t!(s: "there.txt", filestem, Some("there"), opt); - t!(s: "there", filestem, Some("there"), opt); - t!(s: ".", filestem, None, opt); - t!(s: "/", filestem, None, opt); - t!(s: "foo/.bar", filestem, Some(".bar"), opt); - t!(s: ".bar", filestem, Some(".bar"), opt); - t!(s: "..bar", filestem, Some("."), opt); - t!(s: "hi/there..txt", filestem, Some("there."), opt); - t!(s: "..", filestem, None, opt); - t!(s: "../..", filestem, None, opt); - - t!(v: &b"hi/there.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi/there\x80.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi/there.t\x80xt"[..], extension, Some(&b"t\x80xt"[..])); - t!(v: &b"hi/there"[..], extension, None); - t!(v: &b"hi/there\x80"[..], extension, None); - t!(s: "hi/there.txt", extension, Some("txt"), opt); - t!(s: "hi/there", extension, None, opt); - t!(s: "there.txt", extension, Some("txt"), opt); - t!(s: "there", extension, None, opt); - t!(s: ".", extension, None, opt); - t!(s: "/", extension, None, opt); - t!(s: "foo/.bar", extension, None, opt); - t!(s: ".bar", extension, None, opt); - t!(s: "..bar", extension, Some("bar"), opt); - t!(s: "hi/there..txt", extension, Some("txt"), opt); - t!(s: "..", extension, None, opt); - t!(s: "../..", extension, None, opt); - } - - #[test] - fn test_push() { - macro_rules! t { - (s: $path:expr, $join:expr) => ( - { - let path = $path; - let join = $join; - let mut p1 = Path::new(path); - let p2 = p1.clone(); - p1.push(join); - assert_eq!(p1, p2.join(join)); - } - ) - } - - t!(s: "a/b/c", ".."); - t!(s: "/a/b/c", "d"); - t!(s: "a/b", "c/d"); - t!(s: "a/b", "/c/d"); - } - - #[test] - fn test_push_path() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - let push = Path::new($push); - p.push(&push); - assert_eq!(p.as_str(), Some($exp)); - } - ) - } - - t!(s: "a/b/c", "d", "a/b/c/d"); - t!(s: "/a/b/c", "d", "/a/b/c/d"); - t!(s: "a/b", "c/d", "a/b/c/d"); - t!(s: "a/b", "/c/d", "/c/d"); - t!(s: "a/b", ".", "a/b"); - t!(s: "a/b", "../c", "a/c"); - } - - #[test] - fn test_push_many() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_str(), Some($exp)); - } - ); - (v: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_vec(), $exp); - } - ) - } - - t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e"); - t!(s: "a/b/c", ["d", "/e"], "/e"); - t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); - t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"e"[..]], b"a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"/e"[..], &b"f"[..]], b"/e/f"); - t!(v: &b"a/b/c"[..], [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e"); - } - - #[test] - fn test_pop() { - macro_rules! t { - (s: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_str(), Some($left)); - assert_eq!(result, $right); - } - ); - (b: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_vec(), $left); - assert_eq!(result, $right); - } - ) - } - - t!(b: &b"a/b/c"[..], b"a/b", true); - t!(b: &b"a"[..], b".", true); - t!(b: &b"."[..], b".", false); - t!(b: &b"/a"[..], b"/", true); - t!(b: &b"/"[..], b"/", false); - t!(b: &b"a/b/c\x80"[..], b"a/b", true); - t!(b: &b"a/b\x80/c"[..], b"a/b\x80", true); - t!(b: &b"\xFF"[..], b".", true); - t!(b: &b"/\xFF"[..], b"/", true); - t!(s: "a/b/c", "a/b", true); - t!(s: "a", ".", true); - t!(s: ".", ".", false); - t!(s: "/a", "/", true); - t!(s: "/", "/", false); - } - - #[test] - fn test_root_path() { - assert_eq!(Path::new(&b"a/b/c"[..]).root_path(), None); - assert_eq!(Path::new(&b"/a/b/c"[..]).root_path(), Some(Path::new("/"))); - } - - #[test] - fn test_join() { - t!(v: Path::new(&b"a/b/c"[..]).join(&b".."[..]), b"a/b"); - t!(v: Path::new(&b"/a/b/c"[..]).join(&b"d"[..]), b"/a/b/c/d"); - t!(v: Path::new(&b"a/\x80/c"[..]).join(&b"\xFF"[..]), b"a/\x80/c/\xFF"); - t!(s: Path::new("a/b/c").join(".."), "a/b"); - t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d"); - t!(s: Path::new("a/b").join("c/d"), "a/b/c/d"); - t!(s: Path::new("a/b").join("/c/d"), "/c/d"); - t!(s: Path::new(".").join("a/b"), "a/b"); - t!(s: Path::new("/").join("a/b"), "/a/b"); - } - - #[test] - fn test_join_path() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let join = Path::new($join); - let res = path.join(&join); - assert_eq!(res.as_str(), Some($exp)); - } - ) - } - - t!(s: "a/b/c", "..", "a/b"); - t!(s: "/a/b/c", "d", "/a/b/c/d"); - t!(s: "a/b", "c/d", "a/b/c/d"); - t!(s: "a/b", "/c/d", "/c/d"); - t!(s: ".", "a/b", "a/b"); - t!(s: "/", "a/b", "/a/b"); - } - - #[test] - fn test_join_many() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_str(), Some($exp)); - } - ); - (v: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_vec(), $exp); - } - ) - } - - t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e"); - t!(s: "a/b/c", ["..", "d"], "a/b/d"); - t!(s: "a/b/c", ["d", "/e", "f"], "/e/f"); - t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [&b"d"[..], &b"e"[..]], b"a/b/c/d/e"); - t!(v: &b"a/b/c"[..], [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e"); - } - - #[test] - fn test_with_helpers() { - let empty: &[u8] = &[]; - - t!(v: Path::new(&b"a/b/c"[..]).with_filename(&b"d"[..]), b"a/b/d"); - t!(v: Path::new(&b"a/b/c\xFF"[..]).with_filename(&b"\x80"[..]), b"a/b/\x80"); - t!(v: Path::new(&b"/\xFF/foo"[..]).with_filename(&b"\xCD"[..]), - b"/\xFF/\xCD"); - t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d"); - t!(s: Path::new(".").with_filename("foo"), "foo"); - t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d"); - t!(s: Path::new("/").with_filename("foo"), "/foo"); - t!(s: Path::new("/a").with_filename("foo"), "/foo"); - t!(s: Path::new("foo").with_filename("bar"), "bar"); - t!(s: Path::new("/").with_filename("foo/"), "/foo"); - t!(s: Path::new("/a").with_filename("foo/"), "/foo"); - t!(s: Path::new("a/b/c").with_filename(""), "a/b"); - t!(s: Path::new("a/b/c").with_filename("."), "a/b"); - t!(s: Path::new("a/b/c").with_filename(".."), "a"); - t!(s: Path::new("/a").with_filename(""), "/"); - t!(s: Path::new("foo").with_filename(""), "."); - t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e"); - t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d"); - t!(s: Path::new("..").with_filename("foo"), "../foo"); - t!(s: Path::new("../..").with_filename("foo"), "../../foo"); - t!(s: Path::new("..").with_filename(""), ".."); - t!(s: Path::new("../..").with_filename(""), "../.."); - - t!(v: Path::new(&b"hi/there\x80.txt"[..]).with_extension(&b"exe"[..]), - b"hi/there\x80.exe"); - t!(v: Path::new(&b"hi/there.txt\x80"[..]).with_extension(&b"\xFF"[..]), - b"hi/there.\xFF"); - t!(v: Path::new(&b"hi/there\x80"[..]).with_extension(&b"\xFF"[..]), - b"hi/there\x80.\xFF"); - t!(v: Path::new(&b"hi/there.\xFF"[..]).with_extension(empty), b"hi/there"); - t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe"); - t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there"); - t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there.."); - t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there..."); - t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt"); - t!(s: Path::new("hi/there").with_extension("."), "hi/there.."); - t!(s: Path::new("hi/there").with_extension(".."), "hi/there..."); - t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt"); - t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt"); - t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo"); - t!(s: Path::new("/").with_extension("txt"), "/"); - t!(s: Path::new("/").with_extension("."), "/"); - t!(s: Path::new("/").with_extension(".."), "/"); - t!(s: Path::new(".").with_extension("txt"), "."); - } - - #[test] - fn test_setters() { - macro_rules! t { - (s: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ); - (v: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ) - } - - t!(v: &b"a/b/c"[..], set_filename, with_filename, &b"d"[..]); - t!(v: &b"/"[..], set_filename, with_filename, &b"foo"[..]); - t!(v: &b"\x80"[..], set_filename, with_filename, &b"\xFF"[..]); - t!(s: "a/b/c", set_filename, with_filename, "d"); - t!(s: "/", set_filename, with_filename, "foo"); - t!(s: ".", set_filename, with_filename, "foo"); - t!(s: "a/b", set_filename, with_filename, ""); - t!(s: "a", set_filename, with_filename, ""); - - t!(v: &b"hi/there.txt"[..], set_extension, with_extension, &b"exe"[..]); - t!(v: &b"hi/there.t\x80xt"[..], set_extension, with_extension, &b"exe\xFF"[..]); - t!(s: "hi/there.txt", set_extension, with_extension, "exe"); - t!(s: "hi/there.", set_extension, with_extension, "txt"); - t!(s: "hi/there", set_extension, with_extension, "txt"); - t!(s: "hi/there.txt", set_extension, with_extension, ""); - t!(s: "hi/there", set_extension, with_extension, ""); - t!(s: ".", set_extension, with_extension, "txt"); - } - - #[test] - fn test_getters() { - macro_rules! t { - (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename_str(), $filename); - assert_eq!(path.dirname_str(), $dirname); - assert_eq!(path.filestem_str(), $filestem); - assert_eq!(path.extension_str(), $ext); - } - ); - (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename(), $filename); - assert_eq!(path.dirname(), $dirname); - assert_eq!(path.filestem(), $filestem); - assert_eq!(path.extension(), $ext); - } - ) - } - - t!(v: Path::new(&b"a/b/c"[..]), Some(&b"c"[..]), b"a/b", Some(&b"c"[..]), None); - t!(v: Path::new(&b"a/b/\xFF"[..]), Some(&b"\xFF"[..]), b"a/b", Some(&b"\xFF"[..]), None); - t!(v: Path::new(&b"hi/there.\xFF"[..]), Some(&b"there.\xFF"[..]), b"hi", - Some(&b"there"[..]), Some(&b"\xFF"[..])); - t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("/"), None, Some("/"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("../.."), None, Some("../.."), None, None); - t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"), - Some("there"), Some("txt")); - t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None); - t!(s: Path::new("hi/there."), Some("there."), Some("hi"), - Some("there"), Some("")); - t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None); - t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"), - Some("."), Some("there")); - t!(s: Path::new(&b"a/b/\xFF"[..]), None, Some("a/b"), None, None); - t!(s: Path::new(&b"a/b/\xFF.txt"[..]), None, Some("a/b"), None, Some("txt")); - t!(s: Path::new(&b"a/b/c.\x80"[..]), None, Some("a/b"), Some("c"), None); - t!(s: Path::new(&b"\xFF/b"[..]), Some("b"), None, Some("b"), None); - } - - #[test] - fn test_dir_path() { - t!(v: Path::new(&b"hi/there\x80"[..]).dir_path(), b"hi"); - t!(v: Path::new(&b"hi\xFF/there"[..]).dir_path(), b"hi\xFF"); - t!(s: Path::new("hi/there").dir_path(), "hi"); - t!(s: Path::new("hi").dir_path(), "."); - t!(s: Path::new("/hi").dir_path(), "/"); - t!(s: Path::new("/").dir_path(), "/"); - t!(s: Path::new("..").dir_path(), ".."); - t!(s: Path::new("../..").dir_path(), "../.."); - } - - #[test] - fn test_is_absolute() { - macro_rules! t { - (s: $path:expr, $abs:expr, $rel:expr) => ( - { - let path = Path::new($path); - assert_eq!(path.is_absolute(), $abs); - assert_eq!(path.is_relative(), $rel); - } - ) - } - t!(s: "a/b/c", false, true); - t!(s: "/a/b/c", true, false); - t!(s: "a", false, true); - t!(s: "/a", true, false); - t!(s: ".", false, true); - t!(s: "/", true, false); - t!(s: "..", false, true); - t!(s: "../..", false, true); - } - - #[test] - fn test_is_ancestor_of() { - macro_rules! t { - (s: $path:expr, $dest:expr, $exp:expr) => ( - { - let path = Path::new($path); - let dest = Path::new($dest); - assert_eq!(path.is_ancestor_of(&dest), $exp); - } - ) - } - - t!(s: "a/b/c", "a/b/c/d", true); - t!(s: "a/b/c", "a/b/c", true); - t!(s: "a/b/c", "a/b", false); - t!(s: "/a/b/c", "/a/b/c", true); - t!(s: "/a/b", "/a/b/c", true); - t!(s: "/a/b/c/d", "/a/b/c", false); - t!(s: "/a/b", "a/b/c", false); - t!(s: "a/b", "/a/b/c", false); - t!(s: "a/b/c", "a/b/d", false); - t!(s: "../a/b/c", "a/b/c", false); - t!(s: "a/b/c", "../a/b/c", false); - t!(s: "a/b/c", "a/b/cd", false); - t!(s: "a/b/cd", "a/b/c", false); - t!(s: "../a/b", "../a/b/c", true); - t!(s: ".", "a/b", true); - t!(s: ".", ".", true); - t!(s: "/", "/", true); - t!(s: "/", "/a/b", true); - t!(s: "..", "a/b", true); - t!(s: "../..", "a/b", true); - } - - #[test] - fn test_ends_with_path() { - macro_rules! t { - (s: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ); - (v: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ) - } - - t!(s: "a/b/c", "c", true); - t!(s: "a/b/c", "d", false); - t!(s: "foo/bar/quux", "bar", false); - t!(s: "foo/bar/quux", "barquux", false); - t!(s: "a/b/c", "b/c", true); - t!(s: "a/b/c", "a/b/c", true); - t!(s: "a/b/c", "foo/a/b/c", false); - t!(s: "/a/b/c", "a/b/c", true); - t!(s: "/a/b/c", "/a/b/c", false); // child must be relative - t!(s: "/a/b/c", "foo/a/b/c", false); - t!(s: "a/b/c", "", false); - t!(s: "", "", true); - t!(s: "/a/b/c", "d/e/f", false); - t!(s: "a/b/c", "a/b", false); - t!(s: "a/b/c", "b", false); - t!(v: &b"a/b/c"[..], &b"b/c"[..], true); - t!(v: &b"a/b/\xFF"[..], &b"\xFF"[..], true); - t!(v: &b"a/b/\xFF"[..], &b"b/\xFF"[..], true); - } - - #[test] - fn test_path_relative_from() { - macro_rules! t { - (s: $path:expr, $other:expr, $exp:expr) => ( - { - let path = Path::new($path); - let other = Path::new($other); - let res = path.path_relative_from(&other); - assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp); - } - ) - } - - t!(s: "a/b/c", "a/b", Some("c")); - t!(s: "a/b/c", "a/b/d", Some("../c")); - t!(s: "a/b/c", "a/b/c/d", Some("..")); - t!(s: "a/b/c", "a/b/c", Some(".")); - t!(s: "a/b/c", "a/b/c/d/e", Some("../..")); - t!(s: "a/b/c", "a/d/e", Some("../../b/c")); - t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c")); - t!(s: "a/b/c", "/a/b/c", None); - t!(s: "/a/b/c", "a/b/c", Some("/a/b/c")); - t!(s: "/a/b/c", "/a/b/c/d", Some("..")); - t!(s: "/a/b/c", "/a/b", Some("c")); - t!(s: "/a/b/c", "/a/b/c/d/e", Some("../..")); - t!(s: "/a/b/c", "/a/d/e", Some("../../b/c")); - t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c")); - t!(s: "hi/there.txt", "hi/there", Some("../there.txt")); - t!(s: ".", "a", Some("..")); - t!(s: ".", "a/b", Some("../..")); - t!(s: ".", ".", Some(".")); - t!(s: "a", ".", Some("a")); - t!(s: "a/b", ".", Some("a/b")); - t!(s: "..", ".", Some("..")); - t!(s: "a/b/c", "a/b/c", Some(".")); - t!(s: "/a/b/c", "/a/b/c", Some(".")); - t!(s: "/", "/", Some(".")); - t!(s: "/", ".", Some("/")); - t!(s: "../../a", "b", Some("../../../a")); - t!(s: "a", "../../b", None); - t!(s: "../../a", "../../b", Some("../a")); - t!(s: "../../a", "../../a/b", Some("..")); - t!(s: "../../a/b", "../../a", Some("b")); - } - - #[test] - fn test_components_iter() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.components().collect::>(); - let exp: &[&str] = &$exp; - let exps = exp.iter().map(|x| x.as_bytes()).collect::>(); - assert_eq!(comps, exps); - let comps = path.components().rev().collect::>(); - let exps = exps.into_iter().rev().collect::>(); - assert_eq!(comps, exps); - } - ); - (b: $arg:expr, [$($exp:expr),*]) => ( - { - let path = Path::new($arg); - let comps = path.components().collect::>(); - let exp: &[&[u8]] = &[$($exp),*]; - assert_eq!(comps, exp); - let comps = path.components().rev().collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp) - } - ) - } - - t!(b: &b"a/b/c"[..], [b"a", b"b", b"c"]); - t!(b: &b"/\xFF/a/\x80"[..], [b"\xFF", b"a", b"\x80"]); - t!(b: &b"../../foo\xCDbar"[..], [b"..", b"..", b"foo\xCDbar"]); - t!(s: "a/b/c", ["a", "b", "c"]); - t!(s: "a/b/d", ["a", "b", "d"]); - t!(s: "a/b/cd", ["a", "b", "cd"]); - t!(s: "/a/b/c", ["a", "b", "c"]); - t!(s: "a", ["a"]); - t!(s: "/a", ["a"]); - t!(s: "/", []); - t!(s: ".", ["."]); - t!(s: "..", [".."]); - t!(s: "../..", ["..", ".."]); - t!(s: "../../foo", ["..", "..", "foo"]); - } - - #[test] - fn test_str_components() { - macro_rules! t { - (b: $arg:expr, $exp:expr) => ( - { - let path = Path::new($arg); - let comps = path.str_components().collect::>>(); - let exp: &[Option<&str>] = &$exp; - assert_eq!(comps, exp); - let comps = path.str_components().rev().collect::>>(); - let exp = exp.iter().rev().cloned().collect::>>(); - assert_eq!(comps, exp); - } - ) - } - - t!(b: &b"a/b/c"[..], [Some("a"), Some("b"), Some("c")]); - t!(b: &b"/\xFF/a/\x80"[..], [None, Some("a"), None]); - t!(b: &b"../../foo\xCDbar"[..], [Some(".."), Some(".."), None]); - // str_components is a wrapper around components, so no need to do - // the full set of tests - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use self::test::Bencher; - use super::*; - use old_path::GenericPath; - use prelude::v1::Clone; - - #[bench] - fn join_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join("home"); - }); - } - - #[bench] - fn join_abs_path_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join("/home"); - }); - } - - #[bench] - fn join_many_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join_many(&["home"]); - }); - } - - #[bench] - fn join_many_abs_path_home_dir(b: &mut Bencher) { - let posix_path = Path::new("/"); - b.iter(|| { - posix_path.join_many(&["/home"]); - }); - } - - #[bench] - fn push_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push("home"); - }); - } - - #[bench] - fn push_abs_path_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push("/home"); - }); - } - - #[bench] - fn push_many_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push_many(&["home"]); - }); - } - - #[bench] - fn push_many_abs_path_home_dir(b: &mut Bencher) { - let mut posix_path = Path::new("/"); - b.iter(|| { - posix_path.push_many(&["/home"]); - }); - } - - #[bench] - fn ends_with_path_home_dir(b: &mut Bencher) { - let posix_home_path = Path::new("/home"); - b.iter(|| { - posix_home_path.ends_with_path(&Path::new("home")); - }); - } - - #[bench] - fn ends_with_path_missmatch_jome_home(b: &mut Bencher) { - let posix_home_path = Path::new("/home"); - b.iter(|| { - posix_home_path.ends_with_path(&Path::new("jome")); - }); - } - - #[bench] - fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) { - let path = Path::new("/home/1/2/3/4/5/6/7/8/9"); - let mut sub = path.clone(); - sub.pop(); - b.iter(|| { - path.is_ancestor_of(&sub); - }); - } - - #[bench] - fn path_relative_from_forward(b: &mut Bencher) { - let path = Path::new("/a/b/c"); - let mut other = path.clone(); - other.pop(); - b.iter(|| { - path.path_relative_from(&other); - }); - } - - #[bench] - fn path_relative_from_same_level(b: &mut Bencher) { - let path = Path::new("/a/b/c"); - let mut other = path.clone(); - other.pop(); - other.push("d"); - b.iter(|| { - path.path_relative_from(&other); - }); - } - - #[bench] - fn path_relative_from_backward(b: &mut Bencher) { - let path = Path::new("/a/b"); - let mut other = path.clone(); - other.push("c"); - b.iter(|| { - path.path_relative_from(&other); - }); - } -} diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs deleted file mode 100644 index 0b88f368b3..0000000000 --- a/src/libstd/old_path/windows.rs +++ /dev/null @@ -1,2331 +0,0 @@ -// Copyright 2013-2014 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. -// -// ignore-lexer-test FIXME #15883 - -//! Windows file path handling - -use self::PathPrefix::*; - -use ascii::AsciiExt; -use clone::Clone; -use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd}; -use fmt; -use hash; -use old_io::Writer; -use iter::{AdditiveIterator, Extend}; -use iter::{Iterator, Map, repeat}; -use mem; -use option::Option::{self, Some, None}; -use result::Result::{self, Ok, Err}; -use slice::SliceConcatExt; -use str::{SplitTerminator, FromStr}; -use string::{String, ToString}; -use vec::Vec; - -use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &str -/// -/// Each component is yielded as Option<&str> for compatibility with PosixPath, but -/// every component in WindowsPath is guaranteed to be Some. -pub type StrComponents<'a> = - Map, fn(&'a str) -> Option<&'a str>>; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = - Map, fn(Option<&str>) -> &[u8]>; - -/// Represents a Windows path -// Notes for Windows path impl: -// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs -// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information -// about windows paths. -// That same page puts a bunch of restrictions on allowed characters in a path. -// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here -// as `∃P | P.join("\foo.txt") != "\foo.txt"`. -// `C:` is interesting, that means "the current directory on drive C". -// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be -// ignored for now, though, and only added in a hypothetical .to_pwstr() function. -// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the -// processing of "." and ".." components and / as a separator. -// Experimentally, \\?\foo is not the same thing as \foo. -// Also, \\foo is not valid either (certainly not equivalent to \foo). -// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent -// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be -// best to just ignore that and normalize it to C:\foo\bar. -// -// Based on all this, I think the right approach is to do the following: -// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible -// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure). -// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly. -// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing -// server\share. -// * If \\?\, parse disk from following component, if present. Don't error for missing disk. -// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled -// here, they probably aren't, but I'm not going to worry about that. -// * Else if starts with \\, treat following two components as server\share. Don't error for missing -// server\share. -// * Otherwise, attempt to parse drive from start of path. -// -// The only error condition imposed here is valid utf-8. All other invalid paths are simply -// preserved by the data structure; let the Windows API error out on them. -#[derive(Clone)] -pub struct Path { - repr: String, // assumed to never be empty - prefix: Option, - sepidx: Option // index of the final separator in the non-prefix portion of repr -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Path { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.display(), f) - } -} - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { - self.repr == other.repr - } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { - self.repr.cmp(&other.repr) - } -} - -impl FromStr for Path { - type Err = ParsePathError; - fn from_str(s: &str) -> Result { - match Path::new_opt(s) { - Some(p) => Ok(p), - None => Err(ParsePathError), - } - } -} - -/// Value indicating that a path could not be parsed from a string. -#[derive(Debug, Clone, PartialEq, Copy)] -pub struct ParsePathError; - -#[stable(feature = "rust1", since = "1.0.0")] -impl hash::Hash for Path { - #[cfg(not(test))] - #[inline] - fn hash(&self, state: &mut H) { - self.repr.hash(state) - } - - #[cfg(test)] - #[inline] - fn hash(&self, _: &mut H) { - // No-op because the `hash` implementation will be wrong. - } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - self.as_vec() - } - #[inline] - fn container_as_str<'a>(&'a self) -> Option<&'a str> { - self.as_str() - } - #[inline] - fn is_str(_: Option<&Path>) -> bool { true } -} - -impl GenericPathUnsafe for Path { - /// See `GenericPathUnsafe::from_vec_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - #[inline] - unsafe fn new_unchecked(path: T) -> Path { - let (prefix, path) = Path::normalize_(path.container_as_str().unwrap()); - assert!(!path.is_empty()); - let mut ret = Path{ repr: path, prefix: prefix, sepidx: None }; - ret.update_sepidx(); - ret - } - - /// See `GenericPathUnsafe::set_filename_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - unsafe fn set_filename_unchecked(&mut self, filename: T) { - let filename = filename.container_as_str().unwrap(); - match self.sepidx_or_prefix_len() { - None if ".." == self.repr => { - let mut s = String::with_capacity(3 + filename.len()); - s.push_str(".."); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - None => { - self.update_normalized(filename); - } - Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => { - let mut s = String::with_capacity(end + 1 + filename.len()); - s.push_str(&self.repr[..end]); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => { - let mut s = String::with_capacity(idxb + filename.len()); - s.push_str(&self.repr[..idxb]); - s.push_str(filename); - self.update_normalized(&s[..]); - } - Some((idxb,_,_)) => { - let mut s = String::with_capacity(idxb + 1 + filename.len()); - s.push_str(&self.repr[..idxb]); - s.push(SEP); - s.push_str(filename); - self.update_normalized(&s[..]); - } - } - } - - /// See `GenericPathUnsafe::push_unchecked`. - /// - /// Concatenating two Windows Paths is rather complicated. - /// For the most part, it will behave as expected, except in the case of - /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no - /// concept of per-volume cwds like Windows does, we can't behave exactly - /// like Windows will. Instead, if the receiver is an absolute path on - /// the same volume as the new path, it will be treated as the cwd that - /// the new path is relative to. Otherwise, the new path will be treated - /// as if it were absolute and will replace the receiver outright. - unsafe fn push_unchecked(&mut self, path: T) { - let path = path.container_as_str().unwrap(); - fn is_vol_abs(path: &str, prefix: Option) -> bool { - // assume prefix is Some(DiskPrefix) - let rest = &path[prefix_len(prefix)..]; - !rest.is_empty() && rest.as_bytes()[0].is_ascii() && is_sep(rest.as_bytes()[0] as char) - } - fn shares_volume(me: &Path, path: &str) -> bool { - // path is assumed to have a prefix of Some(DiskPrefix) - let repr = &me.repr[..]; - match me.prefix { - Some(DiskPrefix) => { - repr.as_bytes()[0] == path.as_bytes()[0].to_ascii_uppercase() - } - Some(VerbatimDiskPrefix) => { - repr.as_bytes()[4] == path.as_bytes()[0].to_ascii_uppercase() - } - _ => false - } - } - fn is_sep_(prefix: Option, u: u8) -> bool { - if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) } - else { is_sep(u as char) } - } - - fn replace_path(me: &mut Path, path: &str, prefix: Option) { - let newpath = Path::normalize__(path, prefix); - me.repr = match newpath { - Some(p) => p, - None => String::from_str(path) - }; - me.prefix = prefix; - me.update_sepidx(); - } - fn append_path(me: &mut Path, path: &str) { - // appends a path that has no prefix - // if me is verbatim, we need to pre-normalize the new path - let path_ = if is_verbatim(me) { Path::normalize__(path, None) } - else { None }; - let pathlen = path_.as_ref().map_or(path.len(), |p| p.len()); - let mut s = String::with_capacity(me.repr.len() + 1 + pathlen); - s.push_str(&me.repr[..]); - let plen = me.prefix_len(); - // if me is "C:" we don't want to add a path separator - match me.prefix { - Some(DiskPrefix) if me.repr.len() == plen => (), - _ if !(me.repr.len() > plen && me.repr.as_bytes()[me.repr.len()-1] == SEP_BYTE) => { - s.push(SEP); - } - _ => () - } - match path_ { - None => s.push_str(path), - Some(p) => s.push_str(&p[..]), - }; - me.update_normalized(&s[..]) - } - - if !path.is_empty() { - let prefix = parse_prefix(path); - match prefix { - Some(DiskPrefix) if !is_vol_abs(path, prefix) && shares_volume(self, path) => { - // cwd-relative path, self is on the same volume - append_path(self, &path[prefix_len(prefix)..]); - } - Some(_) => { - // absolute path, or cwd-relative and self is not same volume - replace_path(self, path, prefix); - } - None if !path.is_empty() && is_sep_(self.prefix, path.as_bytes()[0]) => { - // volume-relative path - if self.prefix.is_some() { - // truncate self down to the prefix, then append - let n = self.prefix_len(); - self.repr.truncate(n); - append_path(self, path); - } else { - // we have no prefix, so nothing to be relative to - replace_path(self, path, prefix); - } - } - None => { - // relative path - append_path(self, path); - } - } - } - } -} - -impl GenericPath for Path { - #[inline] - fn new_opt(path: T) -> Option { - match path.container_as_str() { - None => None, - Some(ref s) => { - if contains_nul(s) { - None - } else { - Some(unsafe { GenericPathUnsafe::new_unchecked(*s) }) - } - } - } - } - - /// See `GenericPath::as_str` for info. - /// Always returns a `Some` value. - #[inline] - fn as_str<'a>(&'a self) -> Option<&'a str> { - Some(&self.repr[..]) - } - - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { - self.repr.as_bytes() - } - - #[inline] - fn into_vec(self) -> Vec { - self.repr.into_bytes() - } - - #[inline] - fn dirname<'a>(&'a self) -> &'a [u8] { - self.dirname_str().unwrap().as_bytes() - } - - /// See `GenericPath::dirname_str` for info. - /// Always returns a `Some` value. - fn dirname_str<'a>(&'a self) -> Option<&'a str> { - Some(match self.sepidx_or_prefix_len() { - None if ".." == self.repr => &self.repr[..], - None => ".", - Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => { - &self.repr[..] - } - Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => { - &self.repr[..] - } - Some((0,idxa,_)) => &self.repr[..idxa], - Some((idxb,idxa,_)) => { - match self.prefix { - Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => { - &self.repr[..idxa] - } - _ => &self.repr[..idxb] - } - } - }) - } - - #[inline] - fn filename<'a>(&'a self) -> Option<&'a [u8]> { - self.filename_str().map(|x| x.as_bytes()) - } - - /// See `GenericPath::filename_str` for info. - /// Always returns a `Some` value if `filename` returns a `Some` value. - fn filename_str<'a>(&'a self) -> Option<&'a str> { - let repr = &self.repr[..]; - match self.sepidx_or_prefix_len() { - None if "." == repr || ".." == repr => None, - None => Some(repr), - Some((_,idxa,end)) if &repr[idxa..end] == ".." => None, - Some((_,idxa,end)) if idxa == end => None, - Some((_,idxa,end)) => Some(&repr[idxa..end]) - } - } - - /// See `GenericPath::filestem_str` for info. - /// Always returns a `Some` value if `filestem` returns a `Some` value. - #[inline] - fn filestem_str<'a>(&'a self) -> Option<&'a str> { - // filestem() returns a byte vector that's guaranteed valid UTF-8 - self.filestem().map(|t| unsafe { mem::transmute(t) }) - } - - #[inline] - fn extension_str<'a>(&'a self) -> Option<&'a str> { - // extension() returns a byte vector that's guaranteed valid UTF-8 - self.extension().map(|t| unsafe { mem::transmute(t) }) - } - - fn dir_path(&self) -> Path { - unsafe { GenericPathUnsafe::new_unchecked(self.dirname_str().unwrap()) } - } - - #[inline] - fn pop(&mut self) -> bool { - match self.sepidx_or_prefix_len() { - None if "." == self.repr => false, - None => { - self.repr = String::from_str("."); - self.sepidx = None; - true - } - Some((idxb,idxa,end)) if idxb == idxa && idxb == end => false, - Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => false, - Some((idxb,idxa,_)) => { - let trunc = match self.prefix { - Some(DiskPrefix) | Some(VerbatimDiskPrefix) | None => { - let plen = self.prefix_len(); - if idxb == plen { idxa } else { idxb } - } - _ => idxb - }; - self.repr.truncate(trunc); - self.update_sepidx(); - true - } - } - } - - fn root_path(&self) -> Option { - if self.prefix.is_some() { - Some(Path::new(match self.prefix { - Some(DiskPrefix) if self.is_absolute() => { - &self.repr[..self.prefix_len()+1] - } - Some(VerbatimDiskPrefix) => { - &self.repr[..self.prefix_len()+1] - } - _ => &self.repr[..self.prefix_len()] - })) - } else if is_vol_relative(self) { - Some(Path::new(&self.repr[..1])) - } else { - None - } - } - - /// See `GenericPath::is_absolute` for info. - /// - /// A Windows Path is considered absolute only if it has a non-volume prefix, - /// or if it has a volume prefix and the path starts with '\'. - /// A path of `\foo` is not considered absolute because it's actually - /// relative to the "current volume". A separate method `Path::is_vol_relative` - /// is provided to indicate this case. Similarly a path of `C:foo` is not - /// considered absolute because it's relative to the cwd on volume C:. A - /// separate method `Path::is_cwd_relative` is provided to indicate this case. - #[inline] - fn is_absolute(&self) -> bool { - match self.prefix { - Some(DiskPrefix) => { - let rest = &self.repr[self.prefix_len()..]; - rest.len() > 0 && rest.as_bytes()[0] == SEP_BYTE - } - Some(_) => true, - None => false - } - } - - #[inline] - fn is_relative(&self) -> bool { - self.prefix.is_none() && !is_vol_relative(self) - } - - fn is_ancestor_of(&self, other: &Path) -> bool { - if !self.equiv_prefix(other) { - false - } else if self.is_absolute() != other.is_absolute() || - is_vol_relative(self) != is_vol_relative(other) { - false - } else { - let mut ita = self.str_components().map(|x|x.unwrap()); - let mut itb = other.str_components().map(|x|x.unwrap()); - if "." == self.repr { - return itb.next() != Some(".."); - } - loop { - match (ita.next(), itb.next()) { - (None, _) => break, - (Some(a), Some(b)) if a == b => { continue }, - (Some(a), _) if a == ".." => { - // if ita contains only .. components, it's an ancestor - return ita.all(|x| x == ".."); - } - _ => return false - } - } - true - } - } - - fn path_relative_from(&self, base: &Path) -> Option { - fn comp_requires_verbatim(s: &str) -> bool { - s == "." || s == ".." || s.contains(SEP2) - } - - if !self.equiv_prefix(base) { - // prefixes differ - if self.is_absolute() { - Some(self.clone()) - } else if self.prefix == Some(DiskPrefix) && base.prefix == Some(DiskPrefix) { - // both drives, drive letters must differ or they'd be equiv - Some(self.clone()) - } else { - None - } - } else if self.is_absolute() != base.is_absolute() { - if self.is_absolute() { - Some(self.clone()) - } else { - None - } - } else if is_vol_relative(self) != is_vol_relative(base) { - if is_vol_relative(self) { - Some(self.clone()) - } else { - None - } - } else { - let mut ita = self.str_components().map(|x|x.unwrap()); - let mut itb = base.str_components().map(|x|x.unwrap()); - let mut comps = vec![]; - - let a_verb = is_verbatim(self); - let b_verb = is_verbatim(base); - loop { - match (ita.next(), itb.next()) { - (None, None) => break, - (Some(a), None) if a_verb && comp_requires_verbatim(a) => { - return Some(self.clone()) - } - (Some(a), None) => { - comps.push(a); - if !a_verb { - comps.extend(ita.by_ref()); - break; - } - } - (None, _) => comps.push(".."), - (Some(a), Some(b)) if comps.is_empty() && a == b => (), - (Some(a), Some(b)) if !b_verb && b == "." => { - if a_verb && comp_requires_verbatim(a) { - return Some(self.clone()) - } else { comps.push(a) } - } - (Some(_), Some(b)) if !b_verb && b == ".." => return None, - (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => { - return Some(self.clone()) - } - (Some(a), Some(_)) => { - comps.push(".."); - for _ in itb.by_ref() { - comps.push(".."); - } - comps.push(a); - if !a_verb { - comps.extend(ita.by_ref()); - break; - } - } - } - } - Some(Path::new(comps.connect("\\"))) - } - } - - fn ends_with_path(&self, child: &Path) -> bool { - if !child.is_relative() { return false; } - let mut selfit = self.str_components().rev(); - let mut childit = child.str_components().rev(); - loop { - match (selfit.next(), childit.next()) { - (Some(a), Some(b)) => if a != b { return false; }, - (Some(_), None) => break, - (None, Some(_)) => return false, - (None, None) => break - } - } - true - } -} - -impl Path { - /// Returns a new `Path` from a `BytesContainer`. - /// - /// # Panics - /// - /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// println!("{}", Path::new(r"C:\some\path").display()); - /// ``` - #[inline] - pub fn new(path: T) -> Path { - GenericPath::new(path) - } - - /// Returns a new `Some(Path)` from a `BytesContainer`. - /// - /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Examples - /// - /// ``` - /// # #![feature(old_path)] - /// use std::old_path::{Path, GenericPath}; - /// let path = Path::new_opt(r"C:\some\path"); - /// - /// match path { - /// Some(path) => println!("{}", path.display()), - /// None => println!("There was a problem with your path."), - /// } - /// ``` - #[inline] - pub fn new_opt(path: T) -> Option { - GenericPath::new_opt(path) - } - - /// Returns an iterator that yields each component of the path in turn as a Option<&str>. - /// Every component is guaranteed to be Some. - /// Does not yield the path prefix (including server/share components in UNC paths). - /// Does not distinguish between volume-relative and relative paths, e.g. - /// \a\b\c and a\b\c. - /// Does not distinguish between absolute and cwd-relative paths, e.g. - /// C:\foo and C:foo. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { - let repr = &self.repr[..]; - let s = match self.prefix { - Some(_) => { - let plen = self.prefix_len(); - if repr.len() > plen && repr.as_bytes()[plen] == SEP_BYTE { - &repr[plen+1..] - } else { &repr[plen..] } - } - None if repr.as_bytes()[0] == SEP_BYTE => &repr[1..], - None => repr - }; - let some: fn(&'a str) -> Option<&'a str> = Some; // coerce to fn ptr - let ret = s.split_terminator(SEP).map(some); - ret - } - - /// Returns an iterator that yields each component of the path in turn as a &[u8]. - /// See str_components() for details. - pub fn components<'a>(&'a self) -> Components<'a> { - fn convert<'a>(x: Option<&'a str>) -> &'a [u8] { - #![inline] - x.unwrap().as_bytes() - } - let convert: for<'b> fn(Option<&'b str>) -> &'b [u8] = convert; // coerce to fn ptr - self.str_components().map(convert) - } - - fn equiv_prefix(&self, other: &Path) -> bool { - let s_repr = &self.repr[..]; - let o_repr = &other.repr[..]; - match (self.prefix, other.prefix) { - (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => { - self.is_absolute() && - s_repr.as_bytes()[0].to_ascii_lowercase() == - o_repr.as_bytes()[4].to_ascii_lowercase() - } - (Some(VerbatimDiskPrefix), Some(DiskPrefix)) => { - other.is_absolute() && - s_repr.as_bytes()[4].to_ascii_lowercase() == - o_repr.as_bytes()[0].to_ascii_lowercase() - } - (Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => { - s_repr.as_bytes()[4].to_ascii_lowercase() == - o_repr.as_bytes()[4].to_ascii_lowercase() - } - (Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => { - &s_repr[2..self.prefix_len()] == &o_repr[8..other.prefix_len()] - } - (Some(VerbatimUNCPrefix(_,_)), Some(UNCPrefix(_,_))) => { - &s_repr[8..self.prefix_len()] == &o_repr[2..other.prefix_len()] - } - (None, None) => true, - (a, b) if a == b => { - &s_repr[..self.prefix_len()] == &o_repr[..other.prefix_len()] - } - _ => false - } - } - - fn normalize_(s: &str) -> (Option, String) { - // make borrowck happy - let (prefix, val) = { - let prefix = parse_prefix(s); - let path = Path::normalize__(s, prefix); - (prefix, path) - }; - (prefix, match val { - None => s.to_string(), - Some(val) => val - }) - } - - fn normalize__(s: &str, prefix: Option) -> Option { - if prefix_is_verbatim(prefix) { - // don't do any normalization - match prefix { - Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => { - // the server component has no trailing '\' - let mut s = String::from_str(s); - s.push(SEP); - Some(s) - } - _ => None - } - } else { - let (is_abs, comps) = normalize_helper(s, prefix); - let mut comps = comps; - match (comps.is_some(),prefix) { - (false, Some(DiskPrefix)) => { - if s.as_bytes()[0] >= b'a' && s.as_bytes()[0] <= b'z' { - comps = Some(vec![]); - } - } - (false, Some(VerbatimDiskPrefix)) => { - if s.as_bytes()[4] >= b'a' && s.as_bytes()[0] <= b'z' { - comps = Some(vec![]); - } - } - _ => () - } - match comps { - None => None, - Some(comps) => { - if prefix.is_some() && comps.is_empty() { - match prefix.unwrap() { - DiskPrefix => { - let len = prefix_len(prefix) + is_abs as usize; - let mut s = String::from_str(&s[..len]); - unsafe { - let v = s.as_mut_vec(); - v[0] = (*v)[0].to_ascii_uppercase(); - } - if is_abs { - // normalize C:/ to C:\ - unsafe { - s.as_mut_vec()[2] = SEP_BYTE; - } - } - Some(s) - } - VerbatimDiskPrefix => { - let len = prefix_len(prefix) + is_abs as usize; - let mut s = String::from_str(&s[..len]); - unsafe { - let v = s.as_mut_vec(); - v[4] = (*v)[4].to_ascii_uppercase(); - } - Some(s) - } - _ => { - let plen = prefix_len(prefix); - if s.len() > plen { - Some(String::from_str(&s[..plen])) - } else { None } - } - } - } else if is_abs && comps.is_empty() { - Some(repeat(SEP).take(1).collect()) - } else { - let prefix_ = &s[..prefix_len(prefix)]; - let n = prefix_.len() + - if is_abs { comps.len() } else { comps.len() - 1} + - comps.iter().map(|v| v.len()).sum(); - let mut s = String::with_capacity(n); - match prefix { - Some(DiskPrefix) => { - s.push(prefix_.as_bytes()[0].to_ascii_uppercase() as char); - s.push(':'); - } - Some(VerbatimDiskPrefix) => { - s.push_str(&prefix_[..4]); - s.push(prefix_.as_bytes()[4].to_ascii_uppercase() as char); - s.push_str(&prefix_[5..]); - } - Some(UNCPrefix(a,b)) => { - s.push_str("\\\\"); - s.push_str(&prefix_[2..a+2]); - s.push(SEP); - s.push_str(&prefix_[3+a..3+a+b]); - } - Some(_) => s.push_str(prefix_), - None => () - } - let mut it = comps.into_iter(); - if !is_abs { - match it.next() { - None => (), - Some(comp) => s.push_str(comp) - } - } - for comp in it { - s.push(SEP); - s.push_str(comp); - } - Some(s) - } - } - } - } - } - - fn update_sepidx(&mut self) { - let s = if self.has_nonsemantic_trailing_slash() { - &self.repr[..self.repr.len()-1] - } else { &self.repr[..] }; - let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) { - is_sep - } else { - is_sep_verbatim - }; - let idx = s.rfind(sep_test); - let prefixlen = self.prefix_len(); - self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) }); - } - - fn prefix_len(&self) -> usize { - prefix_len(self.prefix) - } - - // Returns a tuple (before, after, end) where before is the index of the separator - // and after is the index just after the separator. - // end is the length of the string, normally, or the index of the final character if it is - // a non-semantic trailing separator in a verbatim string. - // If the prefix is considered the separator, before and after are the same. - fn sepidx_or_prefix_len(&self) -> Option<(usize,usize,usize)> { - match self.sepidx { - None => match self.prefix_len() { 0 => None, x => Some((x,x,self.repr.len())) }, - Some(x) => { - if self.has_nonsemantic_trailing_slash() { - Some((x,x+1,self.repr.len()-1)) - } else { Some((x,x+1,self.repr.len())) } - } - } - } - - fn has_nonsemantic_trailing_slash(&self) -> bool { - is_verbatim(self) && self.repr.len() > self.prefix_len()+1 && - self.repr.as_bytes()[self.repr.len()-1] == SEP_BYTE - } - - fn update_normalized(&mut self, s: &str) { - let (prefix, path) = Path::normalize_(s); - self.repr = path; - self.prefix = prefix; - self.update_sepidx(); - } -} - -/// Returns whether the path is considered "volume-relative", which means a path -/// that looks like "\foo". Paths of this form are relative to the current volume, -/// but absolute within that volume. -#[inline] -pub fn is_vol_relative(path: &Path) -> bool { - path.prefix.is_none() && is_sep_byte(&path.repr.as_bytes()[0]) -} - -/// Returns whether the path is considered "cwd-relative", which means a path -/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths -/// of this form are relative to the cwd on the given volume. -#[inline] -pub fn is_cwd_relative(path: &Path) -> bool { - path.prefix == Some(DiskPrefix) && !path.is_absolute() -} - -/// Returns the PathPrefix for this Path -#[inline] -pub fn prefix(path: &Path) -> Option { - path.prefix -} - -/// Returns whether the Path's prefix is a verbatim prefix, i.e. `\\?\` -#[inline] -pub fn is_verbatim(path: &Path) -> bool { - prefix_is_verbatim(path.prefix) -} - -/// Returns the non-verbatim equivalent of the input path, if possible. -/// If the input path is a device namespace path, None is returned. -/// If the input path is not verbatim, it is returned as-is. -/// If the input path is verbatim, but the same path can be expressed as -/// non-verbatim, the non-verbatim version is returned. -/// Otherwise, None is returned. -pub fn make_non_verbatim(path: &Path) -> Option { - let repr = &path.repr[..]; - let new_path = match path.prefix { - Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None, - Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()), - Some(VerbatimDiskPrefix) => { - // \\?\D:\ - Path::new(&repr[4..]) - } - Some(VerbatimUNCPrefix(_,_)) => { - // \\?\UNC\server\share - Path::new(format!(r"\{}", &repr[7..])) - } - }; - if new_path.prefix.is_none() { - // \\?\UNC\server is a VerbatimUNCPrefix - // but \\server is nothing - return None; - } - // now ensure normalization didn't change anything - if &repr[path.prefix_len()..] == &new_path.repr[new_path.prefix_len()..] { - Some(new_path) - } else { - None - } -} - -/// The standard path separator character -pub const SEP: char = '\\'; -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// The alternative path separator character -pub const SEP2: char = '/'; -/// The alternative path separator character -pub const SEP2_BYTE: u8 = SEP2 as u8; - -/// Returns whether the given char is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep(c: char) -> bool { - c == SEP || c == SEP2 -} - -/// Returns whether the given char is a path separator. -/// Only allows the primary separator '\'; use is_sep to allow '/'. -#[inline] -pub fn is_sep_verbatim(c: char) -> bool { - c == SEP -} - -/// Returns whether the given byte is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { - *u == SEP_BYTE || *u == SEP2_BYTE -} - -/// Returns whether the given byte is a path separator. -/// Only allows the primary separator '\'; use is_sep_byte to allow '/'. -#[inline] -pub fn is_sep_byte_verbatim(u: &u8) -> bool { - *u == SEP_BYTE -} - -/// Prefix types for Path -#[derive(Copy, PartialEq, Clone, Debug)] -pub enum PathPrefix { - /// Prefix `\\?\`, usize is the length of the following component - VerbatimPrefix(usize), - /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components - VerbatimUNCPrefix(usize, usize), - /// Prefix `\\?\C:\` (for any alphabetic character) - VerbatimDiskPrefix, - /// Prefix `\\.\`, usize is the length of the following component - DeviceNSPrefix(usize), - /// UNC prefix `\\server\share`, uints are the lengths of the server/share - UNCPrefix(usize, usize), - /// Prefix `C:` for any alphabetic character - DiskPrefix -} - -fn parse_prefix<'a>(mut path: &'a str) -> Option { - if path.starts_with("\\\\") { - // \\ - path = &path[2..]; - if path.starts_with("?\\") { - // \\?\ - path = &path[2..]; - if path.starts_with("UNC\\") { - // \\?\UNC\server\share - path = &path[4..]; - let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) { - Some(x) => x, - None => (path.len(), 0) - }; - return Some(VerbatimUNCPrefix(idx_a, idx_b)); - } else { - // \\?\path - let idx = path.find('\\'); - if idx == Some(2) && path.as_bytes()[1] == b':' { - let c = path.as_bytes()[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - // \\?\C:\ path - return Some(VerbatimDiskPrefix); - } - } - let idx = idx.unwrap_or(path.len()); - return Some(VerbatimPrefix(idx)); - } - } else if path.starts_with(".\\") { - // \\.\path - path = &path[2..]; - let idx = path.find('\\').unwrap_or(path.len()); - return Some(DeviceNSPrefix(idx)); - } - match parse_two_comps(path, is_sep) { - Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => { - // \\server\share - return Some(UNCPrefix(idx_a, idx_b)); - } - _ => () - } - } else if path.len() > 1 && path.as_bytes()[1] == b':' { - // C: - let c = path.as_bytes()[0]; - if c.is_ascii() && (c as char).is_alphabetic() { - return Some(DiskPrefix); - } - } - return None; - - fn parse_two_comps(mut path: &str, f: fn(char) -> bool) -> Option<(usize, usize)> { - let idx_a = match path.find(f) { - None => return None, - Some(x) => x - }; - path = &path[idx_a+1..]; - let idx_b = path.find(f).unwrap_or(path.len()); - Some((idx_a, idx_b)) - } -} - -// None result means the string didn't need normalizing -fn normalize_helper<'a>(s: &'a str, prefix: Option) -> (bool, Option>) { - let f: fn(char) -> bool = if !prefix_is_verbatim(prefix) { - is_sep - } else { - is_sep_verbatim - }; - let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix))); - let s_ = &s[prefix_len(prefix)..]; - let s_ = if is_abs { &s_[1..] } else { s_ }; - - if is_abs && s_.is_empty() { - return (is_abs, match prefix { - Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None } - else { Some(vec![]) }), - Some(_) => Some(vec![]), // need to trim the trailing separator - }); - } - let mut comps: Vec<&'a str> = vec![]; - let mut n_up = 0; - let mut changed = false; - for comp in s_.split(f) { - if comp.is_empty() { changed = true } - else if comp == "." { changed = true } - else if comp == ".." { - let has_abs_prefix = match prefix { - Some(DiskPrefix) => false, - Some(_) => true, - None => false - }; - if (is_abs || has_abs_prefix) && comps.is_empty() { changed = true } - else if comps.len() == n_up { comps.push(".."); n_up += 1 } - else { comps.pop().unwrap(); changed = true } - } else { comps.push(comp) } - } - if !changed && !prefix_is_verbatim(prefix) { - changed = s.find(is_sep).is_some(); - } - if changed { - if comps.is_empty() && !is_abs && prefix.is_none() { - if s == "." { - return (is_abs, None); - } - comps.push("."); - } - (is_abs, Some(comps)) - } else { - (is_abs, None) - } -} - -fn prefix_is_verbatim(p: Option) -> bool { - match p { - Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true, - Some(DeviceNSPrefix(_)) => true, // not really sure, but I think so - _ => false - } -} - -fn prefix_len(p: Option) -> usize { - match p { - None => 0, - Some(VerbatimPrefix(x)) => 4 + x, - Some(VerbatimUNCPrefix(x,y)) => 8 + x + 1 + y, - Some(VerbatimDiskPrefix) => 6, - Some(UNCPrefix(x,y)) => 2 + x + 1 + y, - Some(DeviceNSPrefix(x)) => 4 + x, - Some(DiskPrefix) => 2 - } -} - -#[cfg(test)] -mod tests { - use super::PathPrefix::*; - use super::parse_prefix; - use super::*; - - use clone::Clone; - use iter::Iterator; - use option::Option::{self, Some, None}; - use old_path::GenericPath; - use string::ToString; - use vec::Vec; - - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_str(), Some($exp)); - } - ); - (v: $path:expr, $exp:expr) => ( - { - let path = $path; - assert_eq!(path.as_vec(), $exp); - } - ) - } - - #[test] - fn test_parse_prefix() { - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = $path; - let exp = $exp; - let res = parse_prefix(path); - assert_eq!(res, exp); - } - ) - } - - t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5))); - t!("\\\\", None); - t!("\\\\SERVER", None); - t!("\\\\SERVER\\", None); - t!("\\\\SERVER\\\\", None); - t!("\\\\SERVER\\\\foo", None); - t!("\\\\SERVER\\share", Some(UNCPrefix(6,5))); - t!("\\\\SERVER/share/foo", Some(UNCPrefix(6,5))); - t!("\\\\SERVER\\share/foo", Some(UNCPrefix(6,5))); - t!("//SERVER/share/foo", None); - t!("\\\\\\a\\b\\c", None); - t!("\\\\?\\a\\b\\c", Some(VerbatimPrefix(1))); - t!("\\\\?\\a/b/c", Some(VerbatimPrefix(5))); - t!("//?/a/b/c", None); - t!("\\\\.\\a\\b", Some(DeviceNSPrefix(1))); - t!("\\\\.\\a/b", Some(DeviceNSPrefix(3))); - t!("//./a/b", None); - t!("\\\\?\\UNC\\server\\share\\foo", Some(VerbatimUNCPrefix(6,5))); - t!("\\\\?\\UNC\\\\share\\foo", Some(VerbatimUNCPrefix(0,5))); - t!("\\\\?\\UNC\\", Some(VerbatimUNCPrefix(0,0))); - t!("\\\\?\\UNC\\server/share/foo", Some(VerbatimUNCPrefix(16,0))); - t!("\\\\?\\UNC\\server", Some(VerbatimUNCPrefix(6,0))); - t!("\\\\?\\UNC\\server\\", Some(VerbatimUNCPrefix(6,0))); - t!("\\\\?\\UNC/server/share", Some(VerbatimPrefix(16))); - t!("\\\\?\\UNC", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:\\a\\b.txt", Some(VerbatimDiskPrefix)); - t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix)); - t!("\\\\?\\C:", Some(VerbatimPrefix(2))); - t!("\\\\?\\C:a.txt", Some(VerbatimPrefix(7))); - t!("\\\\?\\C:a\\b.txt", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:/a", Some(VerbatimPrefix(4))); - t!("C:\\foo", Some(DiskPrefix)); - t!("z:/foo", Some(DiskPrefix)); - t!("d:", Some(DiskPrefix)); - t!("ab:", None); - t!("ü:\\foo", None); - t!("3:\\foo", None); - t!(" :\\foo", None); - t!("::\\foo", None); - t!("\\\\?\\C:", Some(VerbatimPrefix(2))); - t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix)); - t!("\\\\?\\ab:\\", Some(VerbatimPrefix(3))); - t!("\\\\?\\C:\\a", Some(VerbatimDiskPrefix)); - t!("\\\\?\\C:/a", Some(VerbatimPrefix(4))); - t!("\\\\?\\C:\\a/b", Some(VerbatimDiskPrefix)); - } - - #[test] - fn test_paths() { - let empty: &[u8] = &[]; - t!(v: Path::new(empty), b"."); - t!(v: Path::new(&b"\\"[..]), b"\\"); - t!(v: Path::new(&b"a\\b\\c"[..]), b"a\\b\\c"); - - t!(s: Path::new(""), "."); - t!(s: Path::new("\\"), "\\"); - t!(s: Path::new("hi"), "hi"); - t!(s: Path::new("hi\\"), "hi"); - t!(s: Path::new("\\lib"), "\\lib"); - t!(s: Path::new("\\lib\\"), "\\lib"); - t!(s: Path::new("hi\\there"), "hi\\there"); - t!(s: Path::new("hi\\there.txt"), "hi\\there.txt"); - t!(s: Path::new("/"), "\\"); - t!(s: Path::new("hi/"), "hi"); - t!(s: Path::new("/lib"), "\\lib"); - t!(s: Path::new("/lib/"), "\\lib"); - t!(s: Path::new("hi/there"), "hi\\there"); - - t!(s: Path::new("hi\\there\\"), "hi\\there"); - t!(s: Path::new("hi\\..\\there"), "there"); - t!(s: Path::new("hi/../there"), "there"); - t!(s: Path::new("..\\hi\\there"), "..\\hi\\there"); - t!(s: Path::new("\\..\\hi\\there"), "\\hi\\there"); - t!(s: Path::new("/../hi/there"), "\\hi\\there"); - t!(s: Path::new("foo\\.."), "."); - t!(s: Path::new("\\foo\\.."), "\\"); - t!(s: Path::new("\\foo\\..\\.."), "\\"); - t!(s: Path::new("\\foo\\..\\..\\bar"), "\\bar"); - t!(s: Path::new("\\.\\hi\\.\\there\\."), "\\hi\\there"); - t!(s: Path::new("\\.\\hi\\.\\there\\.\\.."), "\\hi"); - t!(s: Path::new("foo\\..\\.."), ".."); - t!(s: Path::new("foo\\..\\..\\.."), "..\\.."); - t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar"); - - assert_eq!(Path::new(&b"foo\\bar"[..]).into_vec(), b"foo\\bar"); - assert_eq!(Path::new(&b"\\foo\\..\\..\\bar"[..]).into_vec(), b"\\bar"); - - t!(s: Path::new("\\\\a"), "\\a"); - t!(s: Path::new("\\\\a\\"), "\\a"); - t!(s: Path::new("\\\\a\\b"), "\\\\a\\b"); - t!(s: Path::new("\\\\a\\b\\"), "\\\\a\\b"); - t!(s: Path::new("\\\\a\\b/"), "\\\\a\\b"); - t!(s: Path::new("\\\\\\b"), "\\b"); - t!(s: Path::new("\\\\a\\\\b"), "\\a\\b"); - t!(s: Path::new("\\\\a\\b\\c"), "\\\\a\\b\\c"); - t!(s: Path::new("\\\\server\\share/path"), "\\\\server\\share\\path"); - t!(s: Path::new("\\\\server/share/path"), "\\\\server\\share\\path"); - t!(s: Path::new("C:a\\b.txt"), "C:a\\b.txt"); - t!(s: Path::new("C:a/b.txt"), "C:a\\b.txt"); - t!(s: Path::new("z:\\a\\b.txt"), "Z:\\a\\b.txt"); - t!(s: Path::new("z:/a/b.txt"), "Z:\\a\\b.txt"); - t!(s: Path::new("ab:/a/b.txt"), "ab:\\a\\b.txt"); - t!(s: Path::new("C:\\"), "C:\\"); - t!(s: Path::new("C:"), "C:"); - t!(s: Path::new("q:"), "Q:"); - t!(s: Path::new("C:/"), "C:\\"); - t!(s: Path::new("C:\\foo\\.."), "C:\\"); - t!(s: Path::new("C:foo\\.."), "C:"); - t!(s: Path::new("C:\\a\\"), "C:\\a"); - t!(s: Path::new("C:\\a/"), "C:\\a"); - t!(s: Path::new("C:\\a\\b\\"), "C:\\a\\b"); - t!(s: Path::new("C:\\a\\b/"), "C:\\a\\b"); - t!(s: Path::new("C:a\\"), "C:a"); - t!(s: Path::new("C:a/"), "C:a"); - t!(s: Path::new("C:a\\b\\"), "C:a\\b"); - t!(s: Path::new("C:a\\b/"), "C:a\\b"); - t!(s: Path::new("\\\\?\\z:\\a\\b.txt"), "\\\\?\\z:\\a\\b.txt"); - t!(s: Path::new("\\\\?\\C:/a/b.txt"), "\\\\?\\C:/a/b.txt"); - t!(s: Path::new("\\\\?\\C:\\a/b.txt"), "\\\\?\\C:\\a/b.txt"); - t!(s: Path::new("\\\\?\\test\\a\\b.txt"), "\\\\?\\test\\a\\b.txt"); - t!(s: Path::new("\\\\?\\foo\\bar\\"), "\\\\?\\foo\\bar\\"); - t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar"); - t!(s: Path::new("\\\\.\\"), "\\\\.\\"); - t!(s: Path::new("\\\\?\\UNC\\server\\share\\foo"), "\\\\?\\UNC\\server\\share\\foo"); - t!(s: Path::new("\\\\?\\UNC\\server/share"), "\\\\?\\UNC\\server/share\\"); - t!(s: Path::new("\\\\?\\UNC\\server"), "\\\\?\\UNC\\server\\"); - t!(s: Path::new("\\\\?\\UNC\\"), "\\\\?\\UNC\\\\"); - t!(s: Path::new("\\\\?\\UNC"), "\\\\?\\UNC"); - - // I'm not sure whether \\.\foo/bar should normalize to \\.\foo\bar - // as information is sparse and this isn't really googleable. - // I'm going to err on the side of not normalizing it, as this skips the filesystem - t!(s: Path::new("\\\\.\\foo/bar"), "\\\\.\\foo/bar"); - t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar"); - } - - #[test] - fn test_opt_paths() { - assert!(Path::new_opt(&b"foo\\bar\0"[..]) == None); - assert!(Path::new_opt(&b"foo\\bar\x80"[..]) == None); - t!(v: Path::new_opt(&b"foo\\bar"[..]).unwrap(), b"foo\\bar"); - assert!(Path::new_opt("foo\\bar\0") == None); - t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar"); - } - - #[test] - fn test_null_byte() { - use thread; - let result = thread::spawn(move|| { - Path::new(&b"foo/bar\0"[..]); - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move|| { - Path::new("test").set_filename(&b"f\0o"[..]) - }).join(); - assert!(result.is_err()); - - let result = thread::spawn(move || { - Path::new("test").push(&b"f\0o"[..]); - }).join(); - assert!(result.is_err()); - } - - #[test] - #[should_panic] - fn test_not_utf8_panics() { - Path::new(&b"hello\x80.txt"[..]); - } - - #[test] - fn test_display_str() { - let path = Path::new("foo"); - assert_eq!(path.display().to_string(), "foo"); - let path = Path::new(&b"\\"[..]); - assert_eq!(path.filename_display().to_string(), ""); - - let path = Path::new("foo"); - let mo = path.display().as_cow(); - assert_eq!(mo, "foo"); - let path = Path::new(&b"\\"[..]); - let mo = path.filename_display().as_cow(); - assert_eq!(mo, ""); - } - - #[test] - fn test_display() { - macro_rules! t { - ($path:expr, $exp:expr, $expf:expr) => ( - { - let path = Path::new($path); - let f = format!("{}", path.display()); - assert_eq!(f, $exp); - let f = format!("{}", path.filename_display()); - assert_eq!(f, $expf); - } - ) - } - - t!("foo", "foo", "foo"); - t!("foo\\bar", "foo\\bar", "bar"); - t!("\\", "\\", ""); - } - - #[test] - fn test_components() { - macro_rules! t { - (s: $path:expr, $op:ident, $exp:expr) => ( - { - let path = $path; - let path = Path::new(path); - assert_eq!(path.$op(), Some($exp)); - } - ); - (s: $path:expr, $op:ident, $exp:expr, opt) => ( - { - let path = $path; - let path = Path::new(path); - let left = path.$op(); - assert_eq!(left, $exp); - } - ); - (v: $path:expr, $op:ident, $exp:expr) => ( - { - let path = $path; - let path = Path::new(path); - assert_eq!(path.$op(), $exp); - } - ) - } - - t!(v: &b"a\\b\\c"[..], filename, Some(&b"c"[..])); - t!(s: "a\\b\\c", filename_str, "c"); - t!(s: "\\a\\b\\c", filename_str, "c"); - t!(s: "a", filename_str, "a"); - t!(s: "\\a", filename_str, "a"); - t!(s: ".", filename_str, None, opt); - t!(s: "\\", filename_str, None, opt); - t!(s: "..", filename_str, None, opt); - t!(s: "..\\..", filename_str, None, opt); - t!(s: "c:\\foo.txt", filename_str, "foo.txt"); - t!(s: "C:\\", filename_str, None, opt); - t!(s: "C:", filename_str, None, opt); - t!(s: "\\\\server\\share\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\server\\share", filename_str, None, opt); - t!(s: "\\\\server", filename_str, "server"); - t!(s: "\\\\?\\bar\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\bar", filename_str, None, opt); - t!(s: "\\\\?\\", filename_str, None, opt); - t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\UNC\\server", filename_str, None, opt); - t!(s: "\\\\?\\UNC\\", filename_str, None, opt); - t!(s: "\\\\?\\C:\\foo.txt", filename_str, "foo.txt"); - t!(s: "\\\\?\\C:\\", filename_str, None, opt); - t!(s: "\\\\?\\C:", filename_str, None, opt); - t!(s: "\\\\?\\foo/bar", filename_str, None, opt); - t!(s: "\\\\?\\C:/foo", filename_str, None, opt); - t!(s: "\\\\.\\foo\\bar", filename_str, "bar"); - t!(s: "\\\\.\\foo", filename_str, None, opt); - t!(s: "\\\\.\\foo/bar", filename_str, None, opt); - t!(s: "\\\\.\\foo\\bar/baz", filename_str, "bar/baz"); - t!(s: "\\\\.\\", filename_str, None, opt); - t!(s: "\\\\?\\a\\b\\", filename_str, "b"); - - t!(v: &b"a\\b\\c"[..], dirname, b"a\\b"); - t!(s: "a\\b\\c", dirname_str, "a\\b"); - t!(s: "\\a\\b\\c", dirname_str, "\\a\\b"); - t!(s: "a", dirname_str, "."); - t!(s: "\\a", dirname_str, "\\"); - t!(s: ".", dirname_str, "."); - t!(s: "\\", dirname_str, "\\"); - t!(s: "..", dirname_str, ".."); - t!(s: "..\\..", dirname_str, "..\\.."); - t!(s: "c:\\foo.txt", dirname_str, "C:\\"); - t!(s: "C:\\", dirname_str, "C:\\"); - t!(s: "C:", dirname_str, "C:"); - t!(s: "C:foo.txt", dirname_str, "C:"); - t!(s: "\\\\server\\share\\foo.txt", dirname_str, "\\\\server\\share"); - t!(s: "\\\\server\\share", dirname_str, "\\\\server\\share"); - t!(s: "\\\\server", dirname_str, "\\"); - t!(s: "\\\\?\\bar\\foo.txt", dirname_str, "\\\\?\\bar"); - t!(s: "\\\\?\\bar", dirname_str, "\\\\?\\bar"); - t!(s: "\\\\?\\", dirname_str, "\\\\?\\"); - t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", dirname_str, "\\\\?\\UNC\\server\\share"); - t!(s: "\\\\?\\UNC\\server", dirname_str, "\\\\?\\UNC\\server\\"); - t!(s: "\\\\?\\UNC\\", dirname_str, "\\\\?\\UNC\\\\"); - t!(s: "\\\\?\\C:\\foo.txt", dirname_str, "\\\\?\\C:\\"); - t!(s: "\\\\?\\C:\\", dirname_str, "\\\\?\\C:\\"); - t!(s: "\\\\?\\C:", dirname_str, "\\\\?\\C:"); - t!(s: "\\\\?\\C:/foo/bar", dirname_str, "\\\\?\\C:/foo/bar"); - t!(s: "\\\\?\\foo/bar", dirname_str, "\\\\?\\foo/bar"); - t!(s: "\\\\.\\foo\\bar", dirname_str, "\\\\.\\foo"); - t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo"); - t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a"); - - t!(v: &b"hi\\there.txt"[..], filestem, Some(&b"there"[..])); - t!(s: "hi\\there.txt", filestem_str, "there"); - t!(s: "hi\\there", filestem_str, "there"); - t!(s: "there.txt", filestem_str, "there"); - t!(s: "there", filestem_str, "there"); - t!(s: ".", filestem_str, None, opt); - t!(s: "\\", filestem_str, None, opt); - t!(s: "foo\\.bar", filestem_str, ".bar"); - t!(s: ".bar", filestem_str, ".bar"); - t!(s: "..bar", filestem_str, "."); - t!(s: "hi\\there..txt", filestem_str, "there."); - t!(s: "..", filestem_str, None, opt); - t!(s: "..\\..", filestem_str, None, opt); - // filestem is based on filename, so we don't need the full set of prefix tests - - t!(v: &b"hi\\there.txt"[..], extension, Some(&b"txt"[..])); - t!(v: &b"hi\\there"[..], extension, None); - t!(s: "hi\\there.txt", extension_str, Some("txt"), opt); - t!(s: "hi\\there", extension_str, None, opt); - t!(s: "there.txt", extension_str, Some("txt"), opt); - t!(s: "there", extension_str, None, opt); - t!(s: ".", extension_str, None, opt); - t!(s: "\\", extension_str, None, opt); - t!(s: "foo\\.bar", extension_str, None, opt); - t!(s: ".bar", extension_str, None, opt); - t!(s: "..bar", extension_str, Some("bar"), opt); - t!(s: "hi\\there..txt", extension_str, Some("txt"), opt); - t!(s: "..", extension_str, None, opt); - t!(s: "..\\..", extension_str, None, opt); - // extension is based on filename, so we don't need the full set of prefix tests - } - - #[test] - fn test_push() { - macro_rules! t { - (s: $path:expr, $join:expr) => ( - { - let path = $path; - let join = $join; - let mut p1 = Path::new(path); - let p2 = p1.clone(); - p1.push(join); - assert_eq!(p1, p2.join(join)); - } - ) - } - - t!(s: "a\\b\\c", ".."); - t!(s: "\\a\\b\\c", "d"); - t!(s: "a\\b", "c\\d"); - t!(s: "a\\b", "\\c\\d"); - // this is just a sanity-check test. push and join share an implementation, - // so there's no need for the full set of prefix tests - - // we do want to check one odd case though to ensure the prefix is re-parsed - let mut p = Path::new("\\\\?\\C:"); - assert_eq!(prefix(&p), Some(VerbatimPrefix(2))); - p.push("foo"); - assert_eq!(prefix(&p), Some(VerbatimDiskPrefix)); - assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo")); - - // and another with verbatim non-normalized paths - let mut p = Path::new("\\\\?\\C:\\a\\"); - p.push("foo"); - assert_eq!(p.as_str(), Some("\\\\?\\C:\\a\\foo")); - } - - #[test] - fn test_push_path() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - let push = Path::new($push); - p.push(&push); - assert_eq!(p.as_str(), Some($exp)); - } - ) - } - - t!(s: "a\\b\\c", "d", "a\\b\\c\\d"); - t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d"); - t!(s: "a\\b", "c\\d", "a\\b\\c\\d"); - t!(s: "a\\b", "\\c\\d", "\\c\\d"); - t!(s: "a\\b", ".", "a\\b"); - t!(s: "a\\b", "..\\c", "a\\c"); - t!(s: "a\\b", "C:a.txt", "C:a.txt"); - t!(s: "a\\b", "..\\..\\..\\c", "..\\c"); - t!(s: "a\\b", "C:\\a.txt", "C:\\a.txt"); - t!(s: "C:\\a", "C:\\b.txt", "C:\\b.txt"); - t!(s: "C:\\a\\b\\c", "C:d", "C:\\a\\b\\c\\d"); - t!(s: "C:a\\b\\c", "C:d", "C:a\\b\\c\\d"); - t!(s: "C:a\\b", "..\\..\\..\\c", "C:..\\c"); - t!(s: "C:\\a\\b", "..\\..\\..\\c", "C:\\c"); - t!(s: "C:", r"a\b\c", r"C:a\b\c"); - t!(s: "C:", r"..\a", r"C:..\a"); - t!(s: "\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); - t!(s: "\\\\server\\share\\foo", "..\\..\\bar", "\\\\server\\share\\bar"); - t!(s: "\\\\server\\share\\foo", "C:baz", "C:baz"); - t!(s: "\\\\?\\C:\\a\\b", "C:c\\d", "\\\\?\\C:\\a\\b\\c\\d"); - t!(s: "\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); - t!(s: "\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); - t!(s: "\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - t!(s: "\\\\?\\C:\\a\\b", "..\\..\\..\\c", "\\\\?\\C:\\a\\b\\..\\..\\..\\c"); - t!(s: "\\\\?\\foo\\bar", "..\\..\\c", "\\\\?\\foo\\bar\\..\\..\\c"); - t!(s: "\\\\?\\", "foo", "\\\\?\\\\foo"); - t!(s: "\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); - t!(s: "\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); - t!(s: "\\\\?\\UNC\\server\\share", "C:a", "C:a"); - t!(s: "\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\\\foo"); - t!(s: "C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); - t!(s: "\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); - t!(s: "\\\\.\\foo\\bar", "C:a", "C:a"); - // again, not sure about the following, but I'm assuming \\.\ should be verbatim - t!(s: "\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); - - t!(s: "\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one - } - - #[test] - fn test_push_many() { - macro_rules! t { - (s: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_str(), Some($exp)); - } - ); - (v: $path:expr, $push:expr, $exp:expr) => ( - { - let mut p = Path::new($path); - p.push_many(&$push); - assert_eq!(p.as_vec(), $exp); - } - ) - } - - t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e"); - t!(s: "a\\b\\c", ["d", "\\e"], "\\e"); - t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); - t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"e"[..]], b"a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"\\e"[..], &b"f"[..]], b"\\e\\f"); - t!(v: &b"a\\b\\c"[..], [b"d".to_vec(), b"e".to_vec()], - b"a\\b\\c\\d\\e"); - } - - #[test] - fn test_pop() { - macro_rules! t { - (s: $path:expr, $left:expr, $right:expr) => ( - { - let pstr = $path; - let mut p = Path::new(pstr); - let result = p.pop(); - let left = $left; - assert_eq!(p.as_str(), Some(left)); - assert_eq!(result, $right); - } - ); - (b: $path:expr, $left:expr, $right:expr) => ( - { - let mut p = Path::new($path); - let result = p.pop(); - assert_eq!(p.as_vec(), $left); - assert_eq!(result, $right); - } - ) - } - - t!(s: "a\\b\\c", "a\\b", true); - t!(s: "a", ".", true); - t!(s: ".", ".", false); - t!(s: "\\a", "\\", true); - t!(s: "\\", "\\", false); - t!(b: &b"a\\b\\c"[..], b"a\\b", true); - t!(b: &b"a"[..], b".", true); - t!(b: &b"."[..], b".", false); - t!(b: &b"\\a"[..], b"\\", true); - t!(b: &b"\\"[..], b"\\", false); - - t!(s: "C:\\a\\b", "C:\\a", true); - t!(s: "C:\\a", "C:\\", true); - t!(s: "C:\\", "C:\\", false); - t!(s: "C:a\\b", "C:a", true); - t!(s: "C:a", "C:", true); - t!(s: "C:", "C:", false); - t!(s: "\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); - t!(s: "\\\\server\\share\\a", "\\\\server\\share", true); - t!(s: "\\\\server\\share", "\\\\server\\share", false); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); - t!(s: "\\\\?\\a\\b", "\\\\?\\a", true); - t!(s: "\\\\?\\a", "\\\\?\\a", false); - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\", true); - t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\", false); - t!(s: "\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); - t!(s: "\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share", true); - t!(s: "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); - t!(s: "\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); - t!(s: "\\\\.\\a\\b", "\\\\.\\a", true); - t!(s: "\\\\.\\a", "\\\\.\\a", false); - - t!(s: "\\\\?\\a\\b\\", "\\\\?\\a", true); - } - - #[test] - fn test_root_path() { - assert_eq!(Path::new("a\\b\\c").root_path(), None); - assert_eq!(Path::new("\\a\\b\\c").root_path(), Some(Path::new("\\"))); - assert_eq!(Path::new("C:a").root_path(), Some(Path::new("C:"))); - assert_eq!(Path::new("C:\\a").root_path(), Some(Path::new("C:\\"))); - assert_eq!(Path::new("\\\\a\\b\\c").root_path(), Some(Path::new("\\\\a\\b"))); - assert_eq!(Path::new("\\\\?\\a\\b").root_path(), Some(Path::new("\\\\?\\a"))); - assert_eq!(Path::new("\\\\?\\C:\\a").root_path(), Some(Path::new("\\\\?\\C:\\"))); - assert_eq!(Path::new("\\\\?\\UNC\\a\\b\\c").root_path(), - Some(Path::new("\\\\?\\UNC\\a\\b"))); - assert_eq!(Path::new("\\\\.\\a\\b").root_path(), Some(Path::new("\\\\.\\a"))); - } - - #[test] - fn test_join() { - t!(s: Path::new("a\\b\\c").join(".."), "a\\b"); - t!(s: Path::new("\\a\\b\\c").join("d"), "\\a\\b\\c\\d"); - t!(s: Path::new("a\\b").join("c\\d"), "a\\b\\c\\d"); - t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d"); - t!(s: Path::new(".").join("a\\b"), "a\\b"); - t!(s: Path::new("\\").join("a\\b"), "\\a\\b"); - t!(v: Path::new(&b"a\\b\\c"[..]).join(&b".."[..]), b"a\\b"); - t!(v: Path::new(&b"\\a\\b\\c"[..]).join(&b"d"[..]), b"\\a\\b\\c\\d"); - // full join testing is covered under test_push_path, so no need for - // the full set of prefix tests - } - - #[test] - fn test_join_path() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let join = Path::new($join); - let res = path.join(&join); - assert_eq!(res.as_str(), Some($exp)); - } - ) - } - - t!(s: "a\\b\\c", "..", "a\\b"); - t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d"); - t!(s: "a\\b", "c\\d", "a\\b\\c\\d"); - t!(s: "a\\b", "\\c\\d", "\\c\\d"); - t!(s: ".", "a\\b", "a\\b"); - t!(s: "\\", "a\\b", "\\a\\b"); - // join is implemented using push, so there's no need for - // the full set of prefix tests - } - - #[test] - fn test_join_many() { - macro_rules! t { - (s: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_str(), Some($exp)); - } - ); - (v: $path:expr, $join:expr, $exp:expr) => ( - { - let path = Path::new($path); - let res = path.join_many(&$join); - assert_eq!(res.as_vec(), $exp); - } - ) - } - - t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e"); - t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d"); - t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f"); - t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [&b"d"[..], &b"e"[..]], b"a\\b\\c\\d\\e"); - t!(v: &b"a\\b\\c"[..], [b"d".to_vec(), b"e".to_vec()], - b"a\\b\\c\\d\\e"); - } - - #[test] - fn test_with_helpers() { - macro_rules! t { - (s: $path:expr, $op:ident, $arg:expr, $res:expr) => ( - { - let pstr = $path; - let path = Path::new(pstr); - let arg = $arg; - let res = path.$op(arg); - let exp = Path::new($res); - assert_eq!(res, exp); - } - ) - } - - t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d"); - t!(s: ".", with_filename, "foo", "foo"); - t!(s: "\\a\\b\\c", with_filename, "d", "\\a\\b\\d"); - t!(s: "\\", with_filename, "foo", "\\foo"); - t!(s: "\\a", with_filename, "foo", "\\foo"); - t!(s: "foo", with_filename, "bar", "bar"); - t!(s: "\\", with_filename, "foo\\", "\\foo"); - t!(s: "\\a", with_filename, "foo\\", "\\foo"); - t!(s: "a\\b\\c", with_filename, "", "a\\b"); - t!(s: "a\\b\\c", with_filename, ".", "a\\b"); - t!(s: "a\\b\\c", with_filename, "..", "a"); - t!(s: "\\a", with_filename, "", "\\"); - t!(s: "foo", with_filename, "", "."); - t!(s: "a\\b\\c", with_filename, "d\\e", "a\\b\\d\\e"); - t!(s: "a\\b\\c", with_filename, "\\d", "a\\b\\d"); - t!(s: "..", with_filename, "foo", "..\\foo"); - t!(s: "..\\..", with_filename, "foo", "..\\..\\foo"); - t!(s: "..", with_filename, "", ".."); - t!(s: "..\\..", with_filename, "", "..\\.."); - t!(s: "C:\\foo\\bar", with_filename, "baz", "C:\\foo\\baz"); - t!(s: "C:\\foo", with_filename, "bar", "C:\\bar"); - t!(s: "C:\\", with_filename, "foo", "C:\\foo"); - t!(s: "C:foo\\bar", with_filename, "baz", "C:foo\\baz"); - t!(s: "C:foo", with_filename, "bar", "C:bar"); - t!(s: "C:", with_filename, "foo", "C:foo"); - t!(s: "C:\\foo", with_filename, "", "C:\\"); - t!(s: "C:foo", with_filename, "", "C:"); - t!(s: "C:\\foo\\bar", with_filename, "..", "C:\\"); - t!(s: "C:\\foo", with_filename, "..", "C:\\"); - t!(s: "C:\\", with_filename, "..", "C:\\"); - t!(s: "C:foo\\bar", with_filename, "..", "C:"); - t!(s: "C:foo", with_filename, "..", "C:.."); - t!(s: "C:", with_filename, "..", "C:.."); - t!(s: "\\\\server\\share\\foo", with_filename, "bar", "\\\\server\\share\\bar"); - t!(s: "\\\\server\\share", with_filename, "foo", "\\\\server\\share\\foo"); - t!(s: "\\\\server\\share\\foo", with_filename, "", "\\\\server\\share"); - t!(s: "\\\\server\\share", with_filename, "", "\\\\server\\share"); - t!(s: "\\\\server\\share\\foo", with_filename, "..", "\\\\server\\share"); - t!(s: "\\\\server\\share", with_filename, "..", "\\\\server\\share"); - t!(s: "\\\\?\\C:\\foo\\bar", with_filename, "baz", "\\\\?\\C:\\foo\\baz"); - t!(s: "\\\\?\\C:\\foo", with_filename, "bar", "\\\\?\\C:\\bar"); - t!(s: "\\\\?\\C:\\", with_filename, "foo", "\\\\?\\C:\\foo"); - t!(s: "\\\\?\\C:\\foo", with_filename, "..", "\\\\?\\C:\\.."); - t!(s: "\\\\?\\foo\\bar", with_filename, "baz", "\\\\?\\foo\\baz"); - t!(s: "\\\\?\\foo", with_filename, "bar", "\\\\?\\foo\\bar"); - t!(s: "\\\\?\\", with_filename, "foo", "\\\\?\\\\foo"); - t!(s: "\\\\?\\foo\\bar", with_filename, "..", "\\\\?\\foo\\.."); - t!(s: "\\\\.\\foo\\bar", with_filename, "baz", "\\\\.\\foo\\baz"); - t!(s: "\\\\.\\foo", with_filename, "bar", "\\\\.\\foo\\bar"); - t!(s: "\\\\.\\foo\\bar", with_filename, "..", "\\\\.\\foo\\.."); - - t!(s: "hi\\there.txt", with_extension, "exe", "hi\\there.exe"); - t!(s: "hi\\there.txt", with_extension, "", "hi\\there"); - t!(s: "hi\\there.txt", with_extension, ".", "hi\\there.."); - t!(s: "hi\\there.txt", with_extension, "..", "hi\\there..."); - t!(s: "hi\\there", with_extension, "txt", "hi\\there.txt"); - t!(s: "hi\\there", with_extension, ".", "hi\\there.."); - t!(s: "hi\\there", with_extension, "..", "hi\\there..."); - t!(s: "hi\\there.", with_extension, "txt", "hi\\there.txt"); - t!(s: "hi\\.foo", with_extension, "txt", "hi\\.foo.txt"); - t!(s: "hi\\there.txt", with_extension, ".foo", "hi\\there..foo"); - t!(s: "\\", with_extension, "txt", "\\"); - t!(s: "\\", with_extension, ".", "\\"); - t!(s: "\\", with_extension, "..", "\\"); - t!(s: ".", with_extension, "txt", "."); - // extension setter calls filename setter internally, no need for extended tests - } - - #[test] - fn test_setters() { - macro_rules! t { - (s: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ); - (v: $path:expr, $set:ident, $with:ident, $arg:expr) => ( - { - let path = $path; - let arg = $arg; - let mut p1 = Path::new(path); - p1.$set(arg); - let p2 = Path::new(path); - assert_eq!(p1, p2.$with(arg)); - } - ) - } - - t!(v: &b"a\\b\\c"[..], set_filename, with_filename, &b"d"[..]); - t!(v: &b"\\"[..], set_filename, with_filename, &b"foo"[..]); - t!(s: "a\\b\\c", set_filename, with_filename, "d"); - t!(s: "\\", set_filename, with_filename, "foo"); - t!(s: ".", set_filename, with_filename, "foo"); - t!(s: "a\\b", set_filename, with_filename, ""); - t!(s: "a", set_filename, with_filename, ""); - - t!(v: &b"hi\\there.txt"[..], set_extension, with_extension, &b"exe"[..]); - t!(s: "hi\\there.txt", set_extension, with_extension, "exe"); - t!(s: "hi\\there.", set_extension, with_extension, "txt"); - t!(s: "hi\\there", set_extension, with_extension, "txt"); - t!(s: "hi\\there.txt", set_extension, with_extension, ""); - t!(s: "hi\\there", set_extension, with_extension, ""); - t!(s: ".", set_extension, with_extension, "txt"); - - // with_ helpers use the setter internally, so the tests for the with_ helpers - // will suffice. No need for the full set of prefix tests. - } - - #[test] - fn test_getters() { - macro_rules! t { - (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename_str(), $filename); - assert_eq!(path.dirname_str(), $dirname); - assert_eq!(path.filestem_str(), $filestem); - assert_eq!(path.extension_str(), $ext); - } - ); - (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => ( - { - let path = $path; - assert_eq!(path.filename(), $filename); - assert_eq!(path.dirname(), $dirname); - assert_eq!(path.filestem(), $filestem); - assert_eq!(path.extension(), $ext); - } - ) - } - - t!(v: Path::new(&b"a\\b\\c"[..]), Some(&b"c"[..]), b"a\\b", Some(&b"c"[..]), None); - t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None); - t!(s: Path::new("."), None, Some("."), None, None); - t!(s: Path::new("\\"), None, Some("\\"), None, None); - t!(s: Path::new(".."), None, Some(".."), None, None); - t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None); - t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"), - Some("there"), Some("txt")); - t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None); - t!(s: Path::new("hi\\there."), Some("there."), Some("hi"), - Some("there"), Some("")); - t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None); - t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"), - Some("."), Some("there")); - - // these are already tested in test_components, so no need for extended tests - } - - #[test] - fn test_dir_path() { - t!(s: Path::new("hi\\there").dir_path(), "hi"); - t!(s: Path::new("hi").dir_path(), "."); - t!(s: Path::new("\\hi").dir_path(), "\\"); - t!(s: Path::new("\\").dir_path(), "\\"); - t!(s: Path::new("..").dir_path(), ".."); - t!(s: Path::new("..\\..").dir_path(), "..\\.."); - - // dir_path is just dirname interpreted as a path. - // No need for extended tests - } - - #[test] - fn test_is_absolute() { - macro_rules! t { - ($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => ( - { - let path = Path::new($path); - let (abs, vol, cwd, rel) = ($abs, $vol, $cwd, $rel); - assert_eq!(path.is_absolute(), abs); - assert_eq!(is_vol_relative(&path), vol); - assert_eq!(is_cwd_relative(&path), cwd); - assert_eq!(path.is_relative(), rel); - } - ) - } - t!("a\\b\\c", false, false, false, true); - t!("\\a\\b\\c", false, true, false, false); - t!("a", false, false, false, true); - t!("\\a", false, true, false, false); - t!(".", false, false, false, true); - t!("\\", false, true, false, false); - t!("..", false, false, false, true); - t!("..\\..", false, false, false, true); - t!("C:a\\b.txt", false, false, true, false); - t!("C:\\a\\b.txt", true, false, false, false); - t!("\\\\server\\share\\a\\b.txt", true, false, false, false); - t!("\\\\?\\a\\b\\c.txt", true, false, false, false); - t!("\\\\?\\C:\\a\\b.txt", true, false, false, false); - t!("\\\\?\\C:a\\b.txt", true, false, false, false); // NB: not equivalent to C:a\b.txt - t!("\\\\?\\UNC\\server\\share\\a\\b.txt", true, false, false, false); - t!("\\\\.\\a\\b", true, false, false, false); - } - - #[test] - fn test_is_ancestor_of() { - macro_rules! t { - (s: $path:expr, $dest:expr, $exp:expr) => ( - { - let path = Path::new($path); - let dest = Path::new($dest); - let exp = $exp; - let res = path.is_ancestor_of(&dest); - assert_eq!(res, exp); - } - ) - } - - t!(s: "a\\b\\c", "a\\b\\c\\d", true); - t!(s: "a\\b\\c", "a\\b\\c", true); - t!(s: "a\\b\\c", "a\\b", false); - t!(s: "\\a\\b\\c", "\\a\\b\\c", true); - t!(s: "\\a\\b", "\\a\\b\\c", true); - t!(s: "\\a\\b\\c\\d", "\\a\\b\\c", false); - t!(s: "\\a\\b", "a\\b\\c", false); - t!(s: "a\\b", "\\a\\b\\c", false); - t!(s: "a\\b\\c", "a\\b\\d", false); - t!(s: "..\\a\\b\\c", "a\\b\\c", false); - t!(s: "a\\b\\c", "..\\a\\b\\c", false); - t!(s: "a\\b\\c", "a\\b\\cd", false); - t!(s: "a\\b\\cd", "a\\b\\c", false); - t!(s: "..\\a\\b", "..\\a\\b\\c", true); - t!(s: ".", "a\\b", true); - t!(s: ".", ".", true); - t!(s: "\\", "\\", true); - t!(s: "\\", "\\a\\b", true); - t!(s: "..", "a\\b", true); - t!(s: "..\\..", "a\\b", true); - t!(s: "foo\\bar", "foobar", false); - t!(s: "foobar", "foo\\bar", false); - - t!(s: "foo", "C:foo", false); - t!(s: "C:foo", "foo", false); - t!(s: "C:foo", "C:foo\\bar", true); - t!(s: "C:foo\\bar", "C:foo", false); - t!(s: "C:\\foo", "C:\\foo\\bar", true); - t!(s: "C:", "C:", true); - t!(s: "C:", "C:\\", false); - t!(s: "C:\\", "C:", false); - t!(s: "C:\\", "C:\\", true); - t!(s: "C:\\foo\\bar", "C:\\foo", false); - t!(s: "C:foo\\bar", "C:foo", false); - t!(s: "C:\\foo", "\\foo", false); - t!(s: "\\foo", "C:\\foo", false); - t!(s: "\\\\server\\share\\foo", "\\\\server\\share\\foo\\bar", true); - t!(s: "\\\\server\\share", "\\\\server\\share\\foo", true); - t!(s: "\\\\server\\share\\foo", "\\\\server\\share", false); - t!(s: "C:\\foo", "\\\\server\\share\\foo", false); - t!(s: "\\\\server\\share\\foo", "C:\\foo", false); - t!(s: "\\\\?\\foo\\bar", "\\\\?\\foo\\bar\\baz", true); - t!(s: "\\\\?\\foo\\bar\\baz", "\\\\?\\foo\\bar", false); - t!(s: "\\\\?\\foo\\bar", "\\foo\\bar\\baz", false); - t!(s: "\\foo\\bar", "\\\\?\\foo\\bar\\baz", false); - t!(s: "\\\\?\\C:\\foo\\bar", "\\\\?\\C:\\foo\\bar\\baz", true); - t!(s: "\\\\?\\C:\\foo\\bar\\baz", "\\\\?\\C:\\foo\\bar", false); - t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\foo", true); - t!(s: "\\\\?\\C:", "\\\\?\\C:\\", false); // this is a weird one - t!(s: "\\\\?\\C:\\", "\\\\?\\C:", false); - t!(s: "\\\\?\\C:\\a", "\\\\?\\c:\\a\\b", true); - t!(s: "\\\\?\\c:\\a", "\\\\?\\C:\\a\\b", true); - t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a\\b", false); - t!(s: "\\\\?\\foo", "\\\\?\\foobar", false); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", true); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\", true); - t!(s: "\\\\?\\a\\b\\", "\\\\?\\a\\b", true); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b\\", false); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c\\d", true); - t!(s: "\\\\?\\UNC\\a\\b\\c\\d", "\\\\?\\UNC\\a\\b\\c", false); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", true); - t!(s: "\\\\.\\foo\\bar", "\\\\.\\foo\\bar\\baz", true); - t!(s: "\\\\.\\foo\\bar\\baz", "\\\\.\\foo\\bar", false); - t!(s: "\\\\.\\foo", "\\\\.\\foo\\bar", true); - t!(s: "\\\\.\\foo", "\\\\.\\foobar", false); - - t!(s: "\\a\\b", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b", "\\a\\b", false); - t!(s: "\\a\\b", "\\\\?\\C:\\a\\b", false); - t!(s: "\\\\?\\C:\\a\\b", "\\a\\b", false); - t!(s: "Z:\\a\\b", "\\\\?\\z:\\a\\b", true); - t!(s: "C:\\a\\b", "\\\\?\\D:\\a\\b", false); - t!(s: "a\\b", "\\\\?\\a\\b", false); - t!(s: "\\\\?\\a\\b", "a\\b", false); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b", true); - t!(s: "\\\\?\\C:\\a\\b", "C:\\a\\b", true); - t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", false); - t!(s: "C:a\\b", "\\\\?\\C:a\\b", false); - t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", false); - t!(s: "\\\\?\\C:a\\b", "C:a\\b", false); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b\\", true); - t!(s: "\\\\?\\C:\\a\\b\\", "C:\\a\\b", true); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c", true); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b\\c", true); - } - - #[test] - fn test_ends_with_path() { - macro_rules! t { - (s: $path:expr, $child:expr, $exp:expr) => ( - { - let path = Path::new($path); - let child = Path::new($child); - assert_eq!(path.ends_with_path(&child), $exp); - } - ); - } - - t!(s: "a\\b\\c", "c", true); - t!(s: "a\\b\\c", "d", false); - t!(s: "foo\\bar\\quux", "bar", false); - t!(s: "foo\\bar\\quux", "barquux", false); - t!(s: "a\\b\\c", "b\\c", true); - t!(s: "a\\b\\c", "a\\b\\c", true); - t!(s: "a\\b\\c", "foo\\a\\b\\c", false); - t!(s: "\\a\\b\\c", "a\\b\\c", true); - t!(s: "\\a\\b\\c", "\\a\\b\\c", false); // child must be relative - t!(s: "\\a\\b\\c", "foo\\a\\b\\c", false); - t!(s: "a\\b\\c", "", false); - t!(s: "", "", true); - t!(s: "\\a\\b\\c", "d\\e\\f", false); - t!(s: "a\\b\\c", "a\\b", false); - t!(s: "a\\b\\c", "b", false); - t!(s: "C:\\a\\b", "b", true); - t!(s: "C:\\a\\b", "C:b", false); - t!(s: "C:\\a\\b", "C:a\\b", false); - } - - #[test] - fn test_path_relative_from() { - macro_rules! t { - (s: $path:expr, $other:expr, $exp:expr) => ( - { - assert_eq!(Path::new($path).path_relative_from(&Path::new($other)) - .as_ref().and_then(|x| x.as_str()), $exp); - } - ) - } - - t!(s: "a\\b\\c", "a\\b", Some("c")); - t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c")); - t!(s: "a\\b\\c", "a\\b\\c\\d", Some("..")); - t!(s: "a\\b\\c", "a\\b\\c", Some(".")); - t!(s: "a\\b\\c", "a\\b\\c\\d\\e", Some("..\\..")); - t!(s: "a\\b\\c", "a\\d\\e", Some("..\\..\\b\\c")); - t!(s: "a\\b\\c", "d\\e\\f", Some("..\\..\\..\\a\\b\\c")); - t!(s: "a\\b\\c", "\\a\\b\\c", None); - t!(s: "\\a\\b\\c", "a\\b\\c", Some("\\a\\b\\c")); - t!(s: "\\a\\b\\c", "\\a\\b\\c\\d", Some("..")); - t!(s: "\\a\\b\\c", "\\a\\b", Some("c")); - t!(s: "\\a\\b\\c", "\\a\\b\\c\\d\\e", Some("..\\..")); - t!(s: "\\a\\b\\c", "\\a\\d\\e", Some("..\\..\\b\\c")); - t!(s: "\\a\\b\\c", "\\d\\e\\f", Some("..\\..\\..\\a\\b\\c")); - t!(s: "hi\\there.txt", "hi\\there", Some("..\\there.txt")); - t!(s: ".", "a", Some("..")); - t!(s: ".", "a\\b", Some("..\\..")); - t!(s: ".", ".", Some(".")); - t!(s: "a", ".", Some("a")); - t!(s: "a\\b", ".", Some("a\\b")); - t!(s: "..", ".", Some("..")); - t!(s: "a\\b\\c", "a\\b\\c", Some(".")); - t!(s: "\\a\\b\\c", "\\a\\b\\c", Some(".")); - t!(s: "\\", "\\", Some(".")); - t!(s: "\\", ".", Some("\\")); - t!(s: "..\\..\\a", "b", Some("..\\..\\..\\a")); - t!(s: "a", "..\\..\\b", None); - t!(s: "..\\..\\a", "..\\..\\b", Some("..\\a")); - t!(s: "..\\..\\a", "..\\..\\a\\b", Some("..")); - t!(s: "..\\..\\a\\b", "..\\..\\a", Some("b")); - - t!(s: "C:a\\b\\c", "C:a\\b", Some("c")); - t!(s: "C:a\\b", "C:a\\b\\c", Some("..")); - t!(s: "C:" ,"C:a\\b", Some("..\\..")); - t!(s: "C:a\\b", "C:c\\d", Some("..\\..\\a\\b")); - t!(s: "C:a\\b", "D:c\\d", Some("C:a\\b")); - t!(s: "C:a\\b", "C:..\\c", None); - t!(s: "C:..\\a", "C:b\\c", Some("..\\..\\..\\a")); - t!(s: "C:\\a\\b\\c", "C:\\a\\b", Some("c")); - t!(s: "C:\\a\\b", "C:\\a\\b\\c", Some("..")); - t!(s: "C:\\", "C:\\a\\b", Some("..\\..")); - t!(s: "C:\\a\\b", "C:\\c\\d", Some("..\\..\\a\\b")); - t!(s: "C:\\a\\b", "C:a\\b", Some("C:\\a\\b")); - t!(s: "C:a\\b", "C:\\a\\b", None); - t!(s: "\\a\\b", "C:\\a\\b", None); - t!(s: "\\a\\b", "C:a\\b", None); - t!(s: "a\\b", "C:\\a\\b", None); - t!(s: "a\\b", "C:a\\b", None); - - t!(s: "\\\\a\\b\\c", "\\\\a\\b", Some("c")); - t!(s: "\\\\a\\b", "\\\\a\\b\\c", Some("..")); - t!(s: "\\\\a\\b\\c\\e", "\\\\a\\b\\c\\d", Some("..\\e")); - t!(s: "\\\\a\\c\\d", "\\\\a\\b\\d", Some("\\\\a\\c\\d")); - t!(s: "\\\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\b\\c\\d")); - t!(s: "\\\\a\\b\\c", "\\d\\e", Some("\\\\a\\b\\c")); - t!(s: "\\d\\e", "\\\\a\\b\\c", None); - t!(s: "d\\e", "\\\\a\\b\\c", None); - t!(s: "C:\\a\\b\\c", "\\\\a\\b\\c", Some("C:\\a\\b\\c")); - t!(s: "C:\\c", "\\\\a\\b\\c", Some("C:\\c")); - - t!(s: "\\\\?\\a\\b", "\\a\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "a\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "\\b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "b", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", Some("c")); - t!(s: "\\\\?\\a\\b", "\\\\?\\c\\d", Some("\\\\?\\a\\b")); - t!(s: "\\\\?\\a", "\\\\?\\b", Some("\\\\?\\a")); - - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\a\\b", Some("..")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\b", Some("..\\a")); - t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a", Some("\\\\?\\C:\\a")); - t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\c:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a\\b", "C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a", "C:\\a\\b", Some("..")); - t!(s: "C:\\a\\b", "\\\\?\\C:\\a", Some("b")); - t!(s: "C:\\a", "\\\\?\\C:\\a\\b", Some("..")); - t!(s: "\\\\?\\C:\\a", "D:\\a", Some("\\\\?\\C:\\a")); - t!(s: "\\\\?\\c:\\a\\b", "C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", Some("\\\\?\\C:\\a\\b")); - t!(s: "\\\\?\\C:\\a\\.\\b", "C:\\a", Some("\\\\?\\C:\\a\\.\\b")); - t!(s: "\\\\?\\C:\\a\\b/c", "C:\\a", Some("\\\\?\\C:\\a\\b/c")); - t!(s: "\\\\?\\C:\\a\\..\\b", "C:\\a", Some("\\\\?\\C:\\a\\..\\b")); - t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", None); - t!(s: "\\\\?\\C:\\a\\.\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\.\\b")); - t!(s: "\\\\?\\C:\\a\\b/c", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\b/c")); - t!(s: "\\\\?\\C:\\a\\..\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\..\\b")); - t!(s: "\\\\?\\C:\\a\\b\\", "\\\\?\\C:\\a", Some("b")); - t!(s: "\\\\?\\C:\\.\\b", "\\\\?\\C:\\.", Some("b")); - t!(s: "C:\\b", "\\\\?\\C:\\.", Some("..\\b")); - t!(s: "\\\\?\\a\\.\\b\\c", "\\\\?\\a\\.\\b", Some("c")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\.\\d", Some("..\\..\\b\\c")); - t!(s: "\\\\?\\a\\..\\b", "\\\\?\\a\\..", Some("b")); - t!(s: "\\\\?\\a\\b\\..", "\\\\?\\a\\b", Some("\\\\?\\a\\b\\..")); - t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\..\\b", Some("..\\..\\b\\c")); - - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c")); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\C:\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d")); - t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\.")); - t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b", Some("c")); - t!(s: "\\\\?\\UNC\\a\\b", "\\\\a\\b\\c", Some("..")); - t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c")); - t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d")); - t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\.")); - t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d")); - t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\..")); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c")); - t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\a\\b\\c")); - } - - #[test] - fn test_str_components() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.str_components().map(|x|x.unwrap()) - .collect::>(); - let exp: &[&str] = &$exp; - assert_eq!(comps, exp); - let comps = path.str_components().rev().map(|x|x.unwrap()) - .collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp); - } - ); - } - - t!(s: &b"a\\b\\c"[..], ["a", "b", "c"]); - t!(s: "a\\b\\c", ["a", "b", "c"]); - t!(s: "a\\b\\d", ["a", "b", "d"]); - t!(s: "a\\b\\cd", ["a", "b", "cd"]); - t!(s: "\\a\\b\\c", ["a", "b", "c"]); - t!(s: "a", ["a"]); - t!(s: "\\a", ["a"]); - t!(s: "\\", []); - t!(s: ".", ["."]); - t!(s: "..", [".."]); - t!(s: "..\\..", ["..", ".."]); - t!(s: "..\\..\\foo", ["..", "..", "foo"]); - t!(s: "C:foo\\bar", ["foo", "bar"]); - t!(s: "C:foo", ["foo"]); - t!(s: "C:", []); - t!(s: "C:\\foo\\bar", ["foo", "bar"]); - t!(s: "C:\\foo", ["foo"]); - t!(s: "C:\\", []); - t!(s: "\\\\server\\share\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\server\\share\\foo", ["foo"]); - t!(s: "\\\\server\\share", []); - t!(s: "\\\\?\\foo\\bar\\baz", ["bar", "baz"]); - t!(s: "\\\\?\\foo\\bar", ["bar"]); - t!(s: "\\\\?\\foo", []); - t!(s: "\\\\?\\", []); - t!(s: "\\\\?\\a\\b", ["b"]); - t!(s: "\\\\?\\a\\b\\", ["b"]); - t!(s: "\\\\?\\foo\\bar\\\\baz", ["bar", "", "baz"]); - t!(s: "\\\\?\\C:\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\?\\C:\\foo", ["foo"]); - t!(s: "\\\\?\\C:\\", []); - t!(s: "\\\\?\\C:\\foo\\", ["foo"]); - t!(s: "\\\\?\\UNC\\server\\share\\foo\\bar", ["foo", "bar"]); - t!(s: "\\\\?\\UNC\\server\\share\\foo", ["foo"]); - t!(s: "\\\\?\\UNC\\server\\share", []); - t!(s: "\\\\.\\foo\\bar\\baz", ["bar", "baz"]); - t!(s: "\\\\.\\foo\\bar", ["bar"]); - t!(s: "\\\\.\\foo", []); - } - - #[test] - fn test_components_iter() { - macro_rules! t { - (s: $path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let comps = path.components().collect::>(); - let exp: &[&[u8]] = &$exp; - assert_eq!(comps, exp); - let comps = path.components().rev().collect::>(); - let exp = exp.iter().rev().cloned().collect::>(); - assert_eq!(comps, exp); - } - ) - } - - t!(s: "a\\b\\c", [b"a", b"b", b"c"]); - t!(s: ".", [b"."]); - // since this is really a wrapper around str_components, those tests suffice - } - - #[test] - fn test_make_non_verbatim() { - macro_rules! t { - ($path:expr, $exp:expr) => ( - { - let path = Path::new($path); - let exp: Option<&str> = $exp; - let exp = exp.map(|s| Path::new(s)); - assert_eq!(make_non_verbatim(&path), exp); - } - ) - } - - t!(r"\a\b\c", Some(r"\a\b\c")); - t!(r"a\b\c", Some(r"a\b\c")); - t!(r"C:\a\b\c", Some(r"C:\a\b\c")); - t!(r"C:a\b\c", Some(r"C:a\b\c")); - t!(r"\\server\share\foo", Some(r"\\server\share\foo")); - t!(r"\\.\foo", None); - t!(r"\\?\foo", None); - t!(r"\\?\C:", None); - t!(r"\\?\C:foo", None); - t!(r"\\?\C:\", Some(r"C:\")); - t!(r"\\?\C:\foo", Some(r"C:\foo")); - t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz")); - t!(r"\\?\C:\foo\.\bar\baz", None); - t!(r"\\?\C:\foo\bar\..\baz", None); - t!(r"\\?\C:\foo\bar\..", None); - t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo")); - t!(r"\\?\UNC\server\share", Some(r"\\server\share")); - t!(r"\\?\UNC\server", None); - t!(r"\\?\UNC\server\", None); - } -} diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 3e0584d9ab..a498e63418 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -26,7 +26,7 @@ thread_local! { } } -pub fn on_panic(obj: &(Any+Send), file: &'static str, line: usize) { +pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) { let msg = match obj.downcast_ref::<&'static str>() { Some(s) => *s, None => match obj.downcast_ref::() { diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 4471b5afa8..e8052041ae 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -103,14 +103,14 @@ use core::prelude::*; use ascii::*; use borrow::{Borrow, IntoCow, ToOwned, Cow}; use cmp; -use iter::{self, IntoIterator}; +use iter; use mem; use ops::{self, Deref}; use string::String; use vec::Vec; use fmt; -use ffi::{OsStr, OsString, AsOsStr}; +use ffi::{OsStr, OsString}; use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; @@ -218,7 +218,7 @@ mod platform { return Some(DeviceNS(u8_slice_as_os_str(slice))); } match parse_two_comps(path, is_sep_byte) { - Some((server, share)) if server.len() > 0 && share.len() > 0 => { + Some((server, share)) if !server.is_empty() && !share.is_empty() => { // \\server\share return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); @@ -312,7 +312,7 @@ impl<'a> Prefix<'a> { } - /// Determine if the prefix is verbatim, i.e. begins `\\?\`. + /// Determines if the prefix is verbatim, i.e. begins `\\?\`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_verbatim(&self) -> bool { @@ -341,7 +341,7 @@ impl<'a> Prefix<'a> { // Exposed parsing helpers //////////////////////////////////////////////////////////////////////////////// -/// Determine whether the character is one of the permitted path +/// Determines whether the character is one of the permitted path /// separators for the current platform. /// /// # Examples @@ -401,7 +401,7 @@ unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { /// Says whether the first byte after the prefix is a separator. fn has_physical_root(s: &[u8], prefix: Option) -> bool { let path = if let Some(p) = prefix { &s[p.len()..] } else { s }; - path.len() > 0 && is_sep_byte(path[0]) + !path.is_empty() && is_sep_byte(path[0]) } // basic workhorse for splitting stem and extension @@ -524,7 +524,7 @@ pub enum Component<'a> { } impl<'a> Component<'a> { - /// Extract the underlying `OsStr` slice + /// Extracts the underlying `OsStr` slice #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(self) -> &'a OsStr { match self { @@ -629,7 +629,7 @@ impl<'a> Components<'a> { } } - /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// Extracts a slice corresponding to the portion of the path remaining for iteration. /// /// # Examples /// @@ -704,7 +704,7 @@ impl<'a> Components<'a> { (comp.len() + extra, self.parse_single_component(comp)) } - // trim away repeated separators (i.e. emtpy components) on the left + // trim away repeated separators (i.e. empty components) on the left fn trim_left(&mut self) { while !self.path.is_empty() { let (size, comp) = self.parse_next_component(); @@ -716,7 +716,7 @@ impl<'a> Components<'a> { } } - // trim away repeated separators (i.e. emtpy components) on the right + // trim away repeated separators (i.e. empty components) on the right fn trim_right(&mut self) { while self.path.len() > self.len_before_body() { let (size, comp) = self.parse_next_component_back(); @@ -750,7 +750,7 @@ impl<'a> AsRef for Components<'a> { } impl<'a> Iter<'a> { - /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// Extracts a slice corresponding to the portion of the path remaining for iteration. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { self.inner.as_path() @@ -810,7 +810,7 @@ impl<'a> Iterator for Components<'a> { State::StartDir => { self.front = State::Body; if self.has_physical_root { - debug_assert!(self.path.len() > 0); + debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; return Some(Component::RootDir) } else if let Some(p) = self.prefix { @@ -818,7 +818,7 @@ impl<'a> Iterator for Components<'a> { return Some(Component::RootDir) } } else if self.include_cur_dir() { - debug_assert!(self.path.len() > 0); + debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; return Some(Component::CurDir) } @@ -941,19 +941,19 @@ impl PathBuf { unsafe { mem::transmute(self) } } - /// Allocate an empty `PathBuf`. + /// Allocates an empty `PathBuf`. #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> PathBuf { PathBuf { inner: OsString::new() } } - /// Coerce to a `Path` slice. + /// Coerces to a `Path` slice. #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &Path { self } - /// Extend `self` with `path`. + /// Extends `self` with `path`. /// /// If `path` is absolute, it replaces the current path. /// @@ -1055,7 +1055,7 @@ impl PathBuf { }; let extension = extension.as_ref(); - if os_str_as_u8_slice(extension).len() > 0 { + if !os_str_as_u8_slice(extension).is_empty() { stem.push("."); stem.push(extension); } @@ -1064,7 +1064,7 @@ impl PathBuf { true } - /// Consume the `PathBuf`, yielding its internal `OsString` storage + /// Consumes the `PathBuf`, yielding its internal `OsString` storage. #[stable(feature = "rust1", since = "1.0.0")] pub fn into_os_string(self) -> OsString { self.inner @@ -1184,14 +1184,6 @@ impl AsRef for PathBuf { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for PathBuf { - fn as_os_str(&self) -> &OsStr { - &self.inner[..] - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Into for PathBuf { fn into(self) -> OsString { @@ -1254,7 +1246,7 @@ impl Path { unsafe { mem::transmute(s.as_ref()) } } - /// Yield the underlying `OsStr` slice. + /// Yields the underlying `OsStr` slice. /// /// # Examples /// @@ -1268,7 +1260,7 @@ impl Path { &self.inner } - /// Yield a `&str` slice if the `Path` is valid unicode. + /// Yields a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// @@ -1284,7 +1276,7 @@ impl Path { self.inner.to_str() } - /// Convert a `Path` to a `Cow`. + /// Converts a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. /// @@ -1300,7 +1292,7 @@ impl Path { self.inner.to_string_lossy() } - /// Convert a `Path` to an owned `PathBuf`. + /// Converts a `Path` to an owned `PathBuf`. /// /// # Examples /// @@ -1477,7 +1469,7 @@ impl Path { iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() } - /// Extract the stem (non-extension) portion of `self.file()`. + /// Extracts the stem (non-extension) portion of `self.file()`. /// /// The stem is: /// @@ -1500,7 +1492,7 @@ impl Path { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) } - /// Extract the extension of `self.file()`, if possible. + /// Extracts the extension of `self.file()`, if possible. /// /// The extension is: /// @@ -1570,11 +1562,12 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/tmp/foo.rs"); /// - /// let new_path = path.with_extension("foo.txt"); + /// let new_path = path.with_extension("txt"); + /// assert_eq!(new_path, PathBuf::from("/tmp/foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { @@ -1651,14 +1644,6 @@ impl AsRef for Path { } } -#[stable(feature = "rust1", since = "1.0.0")] -#[deprecated(since = "1.0.0", reason = "trait is deprecated")] -impl AsOsStr for Path { - fn as_os_str(&self) -> &OsStr { - &self.inner - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Path { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { @@ -1710,22 +1695,6 @@ impl cmp::Ord for Path { } } -/// Freely convertible to a `Path`. -#[unstable(feature = "std_misc")] -#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef instead")] -pub trait AsPath { - /// Convert to a `Path`. - #[unstable(feature = "std_misc")] - fn as_path(&self) -> &Path; -} - -#[unstable(feature = "std_misc")] -#[deprecated(since = "1.0.0", reason = "use std::convert::AsRef instead")] -#[allow(deprecated)] -impl AsPath for T { - fn as_path(&self) -> &Path { Path::new(self.as_os_str()) } -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for Path { fn as_ref(&self) -> &Path { self } diff --git a/src/libstd/prelude/v1.rs b/src/libstd/prelude/v1.rs index 84a4508676..6dc11c505a 100644 --- a/src/libstd/prelude/v1.rs +++ b/src/libstd/prelude/v1.rs @@ -26,17 +26,19 @@ #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] pub use borrow::ToOwned; +#[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use clone::Clone; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; -#[unstable(feature = "convert")] +#[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use convert::{AsRef, AsMut, Into, From}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::DoubleEndedIterator; +#[doc(no_inline)] pub use default::Default; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::ExactSizeIterator; +#[doc(no_inline)] pub use iter::{Iterator, Extend, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] -#[doc(no_inline)] pub use iter::{Iterator, Extend}; +#[doc(no_inline)] pub use iter::{DoubleEndedIterator, ExactSizeIterator}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use option::Option::{self, Some, None}; #[stable(feature = "rust1", since = "1.0.0")] @@ -47,6 +49,3 @@ #[doc(no_inline)] pub use string::{String, ToString}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use vec::Vec; - -#[allow(deprecated)] pub use slice::AsSlice; -#[allow(deprecated)] pub use str::Str; diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 52f5965db8..610b3b3c01 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -19,13 +19,13 @@ use io::prelude::*; use ffi::OsStr; use fmt; use io::{self, Error, ErrorKind}; -use libc; use path; use sync::mpsc::{channel, Receiver}; use sys::pipe2::{self, AnonPipe}; use sys::process2::Command as CommandImp; use sys::process2::Process as ProcessImp; use sys::process2::ExitStatus as ExitStatusImp; +use sys::process2::Stdio as StdioImp2; use sys_common::{AsInner, AsInnerMut}; use thread; @@ -38,8 +38,6 @@ use thread; /// # Examples /// /// ```should_panic -/// # #![feature(process)] -/// /// use std::process::Command; /// /// let output = Command::new("/bin/cat").arg("file.txt").output().unwrap_or_else(|e| { @@ -196,7 +194,7 @@ impl Command { self } - /// Set the working directory for the child process. + /// Sets the working directory for the child process. #[stable(feature = "process", since = "1.0.0")] pub fn current_dir>(&mut self, dir: P) -> &mut Command { self.inner.cwd(dir.as_ref().as_ref()); @@ -229,13 +227,13 @@ impl Command { fn spawn_inner(&self, default_io: StdioImp) -> io::Result { let (their_stdin, our_stdin) = try!( - setup_io(self.stdin.as_ref().unwrap_or(&default_io), 0, true) + setup_io(self.stdin.as_ref().unwrap_or(&default_io), true) ); let (their_stdout, our_stdout) = try!( - setup_io(self.stdout.as_ref().unwrap_or(&default_io), 1, false) + setup_io(self.stdout.as_ref().unwrap_or(&default_io), false) ); let (their_stderr, our_stderr) = try!( - setup_io(self.stderr.as_ref().unwrap_or(&default_io), 2, false) + setup_io(self.stderr.as_ref().unwrap_or(&default_io), false) ); match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) { @@ -267,10 +265,8 @@ impl Command { /// # Examples /// /// ``` - /// # #![feature(process)] /// use std::process::Command; - /// - /// let output = Command::new("cat").arg("foot.txt").output().unwrap_or_else(|e| { + /// let output = Command::new("cat").arg("foo.txt").output().unwrap_or_else(|e| { /// panic!("failed to execute process: {}", e) /// }); /// @@ -291,7 +287,6 @@ impl Command { /// # Examples /// /// ``` - /// # #![feature(process)] /// use std::process::Command; /// /// let status = Command::new("ls").status().unwrap_or_else(|e| { @@ -328,23 +323,19 @@ impl AsInnerMut for Command { fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner } } -fn setup_io(io: &StdioImp, fd: libc::c_int, readable: bool) - -> io::Result<(Option, Option)> +fn setup_io(io: &StdioImp, readable: bool) + -> io::Result<(StdioImp2, Option)> { use self::StdioImp::*; Ok(match *io { - Null => { - (None, None) - } - Inherit => { - (Some(AnonPipe::from_fd(fd)), None) - } + Null => (StdioImp2::None, None), + Inherit => (StdioImp2::Inherit, None), Piped => { - let (reader, writer) = try!(unsafe { pipe2::anon_pipe() }); + let (reader, writer) = try!(pipe2::anon_pipe()); if readable { - (Some(reader), Some(writer)) + (StdioImp2::Piped(reader), Some(writer)) } else { - (Some(writer), Some(reader)) + (StdioImp2::Piped(writer), Some(reader)) } } }) @@ -405,7 +396,7 @@ impl ExitStatus { self.0.success() } - /// Return the exit code of the process, if any. + /// Returns the exit code of the process, if any. /// /// On Unix, this will return `None` if the process was terminated /// by a signal; `std::os::unix` provides an extension trait for @@ -462,7 +453,7 @@ impl Child { unsafe { self.handle.kill() } } - /// Wait for the child to exit completely, returning the status that it + /// Waits for the child to exit completely, returning the status that it /// exited with. This function will continue to have the same return value /// after it has been called at least once. /// @@ -483,7 +474,7 @@ impl Child { } } - /// Simultaneously wait for the child to exit and collect all remaining + /// Simultaneously waits for the child to exit and collect all remaining /// output on the stdout/stderr handles, returning a `Output` /// instance. /// @@ -543,8 +534,6 @@ mod tests { use io::prelude::*; use io::ErrorKind; - use old_path::{self, GenericPath}; - use old_io::fs::PathExtensions; use rt::running_on_valgrind; use str; use super::{Command, Output, Stdio}; @@ -757,43 +746,6 @@ mod tests { cmd } - #[cfg(not(target_arch = "aarch64"))] - #[test] - fn test_keep_current_working_dir() { - use os; - let prog = pwd_cmd().spawn().unwrap(); - - let output = String::from_utf8(prog.wait_with_output().unwrap().stdout).unwrap(); - let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); - let parent_dir = old_path::Path::new(parent_dir); - let child_dir = old_path::Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - - #[test] - fn test_change_working_directory() { - use os; - // test changing to the parent of os::getcwd() because we know - // the path exists (and os::getcwd() is not expected to be root) - let parent_dir = ::env::current_dir().unwrap().to_str().unwrap().to_string(); - let parent_dir = old_path::Path::new(parent_dir).dir_path(); - let result = pwd_cmd().current_dir(parent_dir.as_str().unwrap()).output().unwrap(); - - let output = String::from_utf8(result.stdout).unwrap(); - let child_dir = old_path::Path::new(output.trim()); - - let parent_stat = parent_dir.stat().unwrap(); - let child_stat = child_dir.stat().unwrap(); - - assert_eq!(parent_stat.unstable.device, child_stat.unstable.device); - assert_eq!(parent_stat.unstable.inode, child_stat.unstable.inode); - } - #[cfg(all(unix, not(target_os="android")))] pub fn env_cmd() -> Command { Command::new("env") diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index fad57323d3..e11a581896 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -54,197 +54,24 @@ //! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference //! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` //! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) -//! -//! # Examples -//! -//! ```rust -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::Rng; -//! -//! let mut rng = rand::thread_rng(); -//! if rng.gen() { // random bool -//! println!("isize: {}, usize: {}", rng.gen::(), rng.gen::()) -//! } -//! ``` -//! -//! ```rust -//! # #![feature(rand)] -//! use std::rand; -//! -//! let tuple = rand::random::<(f64, char)>(); -//! println!("{:?}", tuple) -//! ``` -//! -//! ## Monte Carlo estimation of π -//! -//! For this example, imagine we have a square with sides of length 2 and a unit -//! circle, both centered at the origin. Since the area of a unit circle is π, -//! we have: -//! -//! ```text -//! (area of unit circle) / (area of square) = π / 4 -//! ``` -//! -//! So if we sample many points randomly from the square, roughly π / 4 of them -//! should be inside the circle. -//! -//! We can use the above fact to estimate the value of π: pick many points in the -//! square at random, calculate the fraction that fall within the circle, and -//! multiply this fraction by 4. -//! -//! ``` -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! fn main() { -//! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::thread_rng(); -//! -//! let total = 1_000_000; -//! let mut in_circle = 0; -//! -//! for _ in 0..total { -//! let a = between.ind_sample(&mut rng); -//! let b = between.ind_sample(&mut rng); -//! if a*a + b*b <= 1. { -//! in_circle += 1; -//! } -//! } -//! -//! // prints something close to 3.14159... -//! println!("{}", 4. * (in_circle as f64) / (total as f64)); -//! } -//! ``` -//! -//! ## Monty Hall Problem -//! -//! This is a simulation of the [Monty Hall Problem][]: -//! -//! > Suppose you're on a game show, and you're given the choice of three doors: -//! > Behind one door is a car; behind the others, goats. You pick a door, say No. 1, -//! > and the host, who knows what's behind the doors, opens another door, say No. 3, -//! > which has a goat. He then says to you, "Do you want to pick door No. 2?" -//! > Is it to your advantage to switch your choice? -//! -//! The rather unintuitive answer is that you will have a 2/3 chance of winning if -//! you switch and a 1/3 chance of winning if you don't, so it's better to switch. -//! -//! This program will simulate the game show and with large enough simulation steps -//! it will indeed confirm that it is better to switch. -//! -//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem -//! -//! ``` -//! # #![feature(rand)] -//! use std::rand; -//! use std::rand::Rng; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! struct SimulationResult { -//! win: bool, -//! switch: bool, -//! } -//! -//! // Run a single simulation of the Monty Hall problem. -//! fn simulate(random_door: &Range, rng: &mut R) -> SimulationResult { -//! let car = random_door.ind_sample(rng); -//! -//! // This is our initial choice -//! let mut choice = random_door.ind_sample(rng); -//! -//! // The game host opens a door -//! let open = game_host_open(car, choice, rng); -//! -//! // Shall we switch? -//! let switch = rng.gen(); -//! if switch { -//! choice = switch_door(choice, open); -//! } -//! -//! SimulationResult { win: choice == car, switch: switch } -//! } -//! -//! // Returns the door the game host opens given our choice and knowledge of -//! // where the car is. The game host will never open the door with the car. -//! fn game_host_open(car: usize, choice: usize, rng: &mut R) -> usize { -//! let choices = free_doors(&[car, choice]); -//! rand::sample(rng, choices.into_iter(), 1)[0] -//! } -//! -//! // Returns the door we switch to, given our current choice and -//! // the open door. There will only be one valid door. -//! fn switch_door(choice: usize, open: usize) -> usize { -//! free_doors(&[choice, open])[0] -//! } -//! -//! fn free_doors(blocked: &[usize]) -> Vec { -//! (0..3).filter(|x| !blocked.contains(x)).collect() -//! } -//! -//! fn main() { -//! // The estimation will be more accurate with more simulations -//! let num_simulations = 10000; -//! -//! let mut rng = rand::thread_rng(); -//! let random_door = Range::new(0, 3); -//! -//! let (mut switch_wins, mut switch_losses) = (0, 0); -//! let (mut keep_wins, mut keep_losses) = (0, 0); -//! -//! println!("Running {} simulations...", num_simulations); -//! for _ in 0..num_simulations { -//! let result = simulate(&random_door, &mut rng); -//! -//! match (result.win, result.switch) { -//! (true, true) => switch_wins += 1, -//! (true, false) => keep_wins += 1, -//! (false, true) => switch_losses += 1, -//! (false, false) => keep_losses += 1, -//! } -//! } -//! -//! let total_switches = switch_wins + switch_losses; -//! let total_keeps = keep_wins + keep_losses; -//! -//! println!("Switched door {} times with {} wins and {} losses", -//! total_switches, switch_wins, switch_losses); -//! -//! println!("Kept our choice {} times with {} wins and {} losses", -//! total_keeps, keep_wins, keep_losses); -//! -//! // With a large number of simulations, the values should converge to -//! // 0.667 and 0.333 respectively. -//! println!("Estimated chance to win if we switch: {}", -//! switch_wins as f32 / total_switches as f32); -//! println!("Estimated chance to win if we don't: {}", -//! keep_wins as f32 / total_keeps as f32); -//! } -//! ``` #![unstable(feature = "rand")] -#![deprecated(reason = "use the crates.io `rand` library instead", - since = "1.0.0-alpha")] -#![allow(deprecated)] + +use prelude::v1::*; use cell::RefCell; -use clone::Clone; -use old_io::IoResult; -use iter::Iterator; +use io; use mem; use rc::Rc; -use result::Result::{Ok, Err}; -use vec::Vec; #[cfg(target_pointer_width = "32")] use core_rand::IsaacRng as IsaacWordRng; #[cfg(target_pointer_width = "64")] use core_rand::Isaac64Rng as IsaacWordRng; -pub use core_rand::{Rand, Rng, SeedableRng, Open01, Closed01}; -pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng}; -pub use core_rand::{distributions, reseeding}; +pub use core_rand::{Rand, Rng, SeedableRng}; +pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng}; +pub use core_rand::reseeding; pub use rand::os::OsRng; pub mod os; @@ -269,7 +96,7 @@ impl StdRng { /// /// Reading the randomness from the OS may fail, and any error is /// propagated via the `IoResult` return value. - pub fn new() -> IoResult { + pub fn new() -> io::Result { OsRng::new().map(|mut r| StdRng { rng: r.gen() }) } } @@ -298,22 +125,6 @@ impl<'a> SeedableRng<&'a [usize]> for StdRng { } } -/// Create a weak random number generator with a default algorithm and seed. -/// -/// It returns the fastest `Rng` algorithm currently available in Rust without -/// consideration for cryptography or security. If you require a specifically -/// seeded `Rng` for consistency over time you should pick one algorithm and -/// create the `Rng` yourself. -/// -/// This will read randomness from the operating system to seed the -/// generator. -pub fn weak_rng() -> XorShiftRng { - match OsRng::new() { - Ok(mut r) => r.gen(), - Err(e) => panic!("weak_rng: failed to create seeded RNG: {:?}", e) - } -} - /// Controls how the thread-local RNG is reseeded. struct ThreadRngReseeder; @@ -375,338 +186,3 @@ impl Rng for ThreadRng { self.rng.borrow_mut().fill_bytes(bytes) } } - -/// Generates a random value using the thread-local random number generator. -/// -/// `random()` can generate various types of random things, and so may require -/// type hinting to generate the specific type you want. -/// -/// This function uses the thread local random number generator. This means -/// that if you're calling `random()` in a loop, caching the generator can -/// increase performance. An example is shown below. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// -/// let x: u8 = rand::random(); -/// println!("{}", 2 * x as u16); -/// -/// let y = rand::random::(); -/// println!("{}", y); -/// -/// if rand::random() { // generates a boolean -/// println!("Better lucky than good!"); -/// } -/// ``` -/// -/// Caching the thread local random number generator: -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand; -/// use std::rand::Rng; -/// -/// let mut v = vec![1, 2, 3]; -/// -/// for x in v.iter_mut() { -/// *x = rand::random() -/// } -/// -/// // would be faster as -/// -/// let mut rng = rand::thread_rng(); -/// -/// for x in v.iter_mut() { -/// *x = rng.gen(); -/// } -/// ``` -#[inline] -pub fn random() -> T { - thread_rng().gen() -} - -/// Randomly sample up to `amount` elements from an iterator. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand)] -/// use std::rand::{thread_rng, sample}; -/// -/// let mut rng = thread_rng(); -/// let sample = sample(&mut rng, 1..100, 5); -/// println!("{:?}", sample); -/// ``` -pub fn sample, R: Rng>(rng: &mut R, - mut iter: I, - amount: usize) -> Vec { - let mut reservoir: Vec = iter.by_ref().take(amount).collect(); - for (i, elem) in iter.enumerate() { - let k = rng.gen_range(0, i + 1 + amount); - if k < amount { - reservoir[k] = elem; - } - } - return reservoir; -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - use super::{Rng, thread_rng, random, SeedableRng, StdRng, sample}; - use iter::{order, repeat}; - - struct ConstRng { i: u64 } - impl Rng for ConstRng { - fn next_u32(&mut self) -> u32 { self.i as u32 } - fn next_u64(&mut self) -> u64 { self.i } - - // no fill_bytes on purpose - } - - #[test] - fn test_fill_bytes_default() { - let mut r = ConstRng { i: 0x11_22_33_44_55_66_77_88 }; - - // check every remainder mod 8, both in small and big vectors. - let lengths = [0, 1, 2, 3, 4, 5, 6, 7, - 80, 81, 82, 83, 84, 85, 86, 87]; - for &n in &lengths { - let mut v = repeat(0).take(n).collect::>(); - r.fill_bytes(&mut v); - - // use this to get nicer error messages. - for (i, &byte) in v.iter().enumerate() { - if byte == 0 { - panic!("byte {} of {} is zero", i, n) - } - } - } - } - - #[test] - fn test_gen_range() { - let mut r = thread_rng(); - for _ in 0..1000 { - let a = r.gen_range(-3, 42); - assert!(a >= -3 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); - assert_eq!(r.gen_range(-12, -11), -12); - } - - for _ in 0..1000 { - let a = r.gen_range(10, 42); - assert!(a >= 10 && a < 42); - assert_eq!(r.gen_range(0, 1), 0); - assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000); - } - - } - - #[test] - #[should_panic] - fn test_gen_range_panic_int() { - let mut r = thread_rng(); - r.gen_range(5, -2); - } - - #[test] - #[should_panic] - fn test_gen_range_panic_uint() { - let mut r = thread_rng(); - r.gen_range(5, 2); - } - - #[test] - fn test_gen_f64() { - let mut r = thread_rng(); - let a = r.gen::(); - let b = r.gen::(); - debug!("{:?}", (a, b)); - } - - #[test] - fn test_gen_weighted_bool() { - let mut r = thread_rng(); - assert_eq!(r.gen_weighted_bool(0), true); - assert_eq!(r.gen_weighted_bool(1), true); - } - - #[test] - fn test_gen_ascii_str() { - let mut r = thread_rng(); - assert_eq!(r.gen_ascii_chars().take(0).count(), 0); - assert_eq!(r.gen_ascii_chars().take(10).count(), 10); - assert_eq!(r.gen_ascii_chars().take(16).count(), 16); - } - - #[test] - fn test_gen_vec() { - let mut r = thread_rng(); - assert_eq!(r.gen_iter::().take(0).count(), 0); - assert_eq!(r.gen_iter::().take(10).count(), 10); - assert_eq!(r.gen_iter::().take(16).count(), 16); - } - - #[test] - fn test_choose() { - let mut r = thread_rng(); - assert_eq!(r.choose(&[1, 1, 1]).cloned(), Some(1)); - - let v: &[isize] = &[]; - assert_eq!(r.choose(v), None); - } - - #[test] - fn test_shuffle() { - let mut r = thread_rng(); - let empty: &mut [isize] = &mut []; - r.shuffle(empty); - let mut one = [1]; - r.shuffle(&mut one); - let b: &[_] = &[1]; - assert_eq!(one, b); - - let mut two = [1, 2]; - r.shuffle(&mut two); - assert!(two == [1, 2] || two == [2, 1]); - - let mut x = [1, 1, 1]; - r.shuffle(&mut x); - let b: &[_] = &[1, 1, 1]; - assert_eq!(x, b); - } - - #[test] - fn test_thread_rng() { - let mut r = thread_rng(); - r.gen::(); - let mut v = [1, 1, 1]; - r.shuffle(&mut v); - let b: &[_] = &[1, 1, 1]; - assert_eq!(v, b); - assert_eq!(r.gen_range(0, 1), 0); - } - - #[test] - fn test_random() { - // not sure how to test this aside from just getting some values - let _n : usize = random(); - let _f : f32 = random(); - let _o : Option> = random(); - let _many : ((), - (usize, - isize, - Option<(u32, (bool,))>), - (u8, i8, u16, i16, u32, i32, u64, i64), - (f32, (f64, (f64,)))) = random(); - } - - #[test] - fn test_sample() { - let min_val = 1; - let max_val = 100; - - let mut r = thread_rng(); - let vals = (min_val..max_val).collect::>(); - let small_sample = sample(&mut r, vals.iter(), 5); - let large_sample = sample(&mut r, vals.iter(), vals.len() + 5); - - assert_eq!(small_sample.len(), 5); - assert_eq!(large_sample.len(), vals.len()); - - assert!(small_sample.iter().all(|e| { - **e >= min_val && **e <= max_val - })); - } - - #[test] - fn test_std_rng_seeded() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut ra: StdRng = SeedableRng::from_seed(&*s); - let mut rb: StdRng = SeedableRng::from_seed(&*s); - assert!(order::equals(ra.gen_ascii_chars().take(100), - rb.gen_ascii_chars().take(100))); - } - - #[test] - fn test_std_rng_reseed() { - let s = thread_rng().gen_iter::().take(256).collect::>(); - let mut r: StdRng = SeedableRng::from_seed(&*s); - let string1 = r.gen_ascii_chars().take(100).collect::(); - - r.reseed(&s); - - let string2 = r.gen_ascii_chars().take(100).collect::(); - assert_eq!(string1, string2); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - use prelude::v1::*; - - use self::test::Bencher; - use super::{XorShiftRng, StdRng, IsaacRng, Isaac64Rng, Rng}; - use super::{OsRng, weak_rng}; - use mem::size_of; - - const RAND_BENCH_N: u64 = 100; - - #[bench] - fn rand_xorshift(b: &mut Bencher) { - let mut rng: XorShiftRng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_isaac(b: &mut Bencher) { - let mut rng: IsaacRng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_isaac64(b: &mut Bencher) { - let mut rng: Isaac64Rng = OsRng::new().unwrap().gen(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_std(b: &mut Bencher) { - let mut rng = StdRng::new().unwrap(); - b.iter(|| { - for _ in 0..RAND_BENCH_N { - rng.gen::(); - } - }); - b.bytes = size_of::() as u64 * RAND_BENCH_N; - } - - #[bench] - fn rand_shuffle_100(b: &mut Bencher) { - let mut rng = weak_rng(); - let x : &mut[usize] = &mut [1; 100]; - b.iter(|| { - rng.shuffle(x); - }) - } -} diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 38c57eec68..6c10759023 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -18,10 +18,10 @@ mod imp { use prelude::v1::*; use self::OsRngInner::*; + use fs::File; + use io; use libc; use mem; - use old_io::{IoResult, File}; - use old_path::Path; use rand::Rng; use rand::reader::ReaderRng; use sys::os::errno; @@ -147,12 +147,12 @@ mod imp { impl OsRng { /// Create a new `OsRng`. - pub fn new() -> IoResult { + pub fn new() -> io::Result { if is_getrandom_available() { return Ok(OsRng { inner: OsGetrandomRng }); } - let reader = try!(File::open(&Path::new("/dev/urandom"))); + let reader = try!(File::open("/dev/urandom")); let reader_rng = ReaderRng::new(reader); Ok(OsRng { inner: OsReaderRng(reader_rng) }) @@ -186,7 +186,6 @@ mod imp { use prelude::v1::*; use io; - use old_io::IoResult; use mem; use rand::Rng; use libc::{c_int, size_t}; @@ -202,7 +201,8 @@ mod imp { /// /// This does not block. pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside of this module + // dummy field to ensure that this struct cannot be constructed outside + // of this module _dummy: (), } @@ -220,7 +220,7 @@ mod imp { impl OsRng { /// Create a new `OsRng`. - pub fn new() -> IoResult { + pub fn new() -> io::Result { Ok(OsRng { _dummy: () }) } } @@ -238,10 +238,12 @@ mod imp { } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) + SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, + v.as_mut_ptr()) }; if ret == -1 { - panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); } } } @@ -253,7 +255,6 @@ mod imp { use io; use mem; - use old_io::{IoResult, IoError}; use rand::Rng; use libc::types::os::arch::extra::{LONG_PTR}; use libc::{DWORD, BYTE, LPCSTR, BOOL}; @@ -293,7 +294,7 @@ mod imp { impl OsRng { /// Create a new `OsRng`. - pub fn new() -> IoResult { + pub fn new() -> io::Result { let mut hcp = 0; let ret = unsafe { CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR, @@ -302,7 +303,7 @@ mod imp { }; if ret == 0 { - Err(IoError::last_error()) + Err(io::Error::last_os_error()) } else { Ok(OsRng { hcryptprov: hcp }) } diff --git a/src/libstd/rand/reader.rs b/src/libstd/rand/reader.rs index ece6867ddc..2837bac445 100644 --- a/src/libstd/rand/reader.rs +++ b/src/libstd/rand/reader.rs @@ -8,35 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A wrapper around any Reader to treat it as an RNG. +//! A wrapper around any Read to treat it as an RNG. -use old_io::Reader; +#![allow(dead_code)] + +use prelude::v1::*; +use io::prelude::*; use rand::Rng; -use result::Result::{Ok, Err}; -/// An RNG that reads random bytes straight from a `Reader`. This will +/// An RNG that reads random bytes straight from a `Read`. This will /// work best with an infinite reader, but this is not required. /// /// # Panics /// /// It will panic if it there is insufficient data to fulfill a request. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rand, old_io)] -/// use std::rand::{reader, Rng}; -/// use std::old_io::MemReader; -/// -/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8))); -/// println!("{:x}", rng.gen::()); -/// ``` pub struct ReaderRng { reader: R } -impl ReaderRng { - /// Create a new `ReaderRng` from a `Reader`. +impl ReaderRng { + /// Create a new `ReaderRng` from a `Read`. pub fn new(r: R) -> ReaderRng { ReaderRng { reader: r @@ -44,30 +35,29 @@ impl ReaderRng { } } -impl Rng for ReaderRng { +impl Rng for ReaderRng { fn next_u32(&mut self) -> u32 { // This is designed for speed: reading a LE integer on a LE // platform just involves blitting the bytes into the memory // of the u32, similarly for BE on BE; avoiding byteswapping. - if cfg!(target_endian="little") { - self.reader.read_le_u32().unwrap() - } else { - self.reader.read_be_u32().unwrap() - } + let mut bytes = [0; 4]; + self.fill_bytes(&mut bytes); + unsafe { *(bytes.as_ptr() as *const u32) } } fn next_u64(&mut self) -> u64 { // see above for explanation. - if cfg!(target_endian="little") { - self.reader.read_le_u64().unwrap() - } else { - self.reader.read_be_u64().unwrap() - } + let mut bytes = [0; 8]; + self.fill_bytes(&mut bytes); + unsafe { *(bytes.as_ptr() as *const u64) } } - fn fill_bytes(&mut self, v: &mut [u8]) { - if v.len() == 0 { return } - match self.reader.read_at_least(v.len(), v) { - Ok(_) => {} - Err(e) => panic!("ReaderRng.fill_bytes error: {:?}", e) + fn fill_bytes(&mut self, mut v: &mut [u8]) { + while !v.is_empty() { + let t = v; + match self.reader.read(t) { + Ok(0) => panic!("ReaderRng.fill_bytes: EOF reached"), + Ok(n) => v = t.split_at_mut(n).1, + Err(e) => panic!("ReaderRng.fill_bytes: {}", e), + } } } } @@ -77,37 +67,35 @@ mod test { use prelude::v1::*; use super::ReaderRng; - use old_io::MemReader; - use num::Int; use rand::Rng; #[test] fn test_reader_rng_u64() { // transmute from the target to avoid endianness concerns. - let v = vec![0, 0, 0, 0, 0, 0, 0, 1, - 0 , 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); + let v = &[0, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3][..]; + let mut rng = ReaderRng::new(v); - assert_eq!(rng.next_u64(), 1.to_be()); - assert_eq!(rng.next_u64(), 2.to_be()); - assert_eq!(rng.next_u64(), 3.to_be()); + assert_eq!(rng.next_u64(), 1u64.to_be()); + assert_eq!(rng.next_u64(), 2u64.to_be()); + assert_eq!(rng.next_u64(), 3u64.to_be()); } #[test] fn test_reader_rng_u32() { - let v = vec![0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); + let v = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3][..]; + let mut rng = ReaderRng::new(v); - assert_eq!(rng.next_u32(), 1.to_be()); - assert_eq!(rng.next_u32(), 2.to_be()); - assert_eq!(rng.next_u32(), 3.to_be()); + assert_eq!(rng.next_u32(), 1u32.to_be()); + assert_eq!(rng.next_u32(), 2u32.to_be()); + assert_eq!(rng.next_u32(), 3u32.to_be()); } #[test] fn test_reader_rng_fill_bytes() { let v = [1, 2, 3, 4, 5, 6, 7, 8]; let mut w = [0; 8]; - let mut rng = ReaderRng::new(MemReader::new(v.to_vec())); + let mut rng = ReaderRng::new(&v[..]); rng.fill_bytes(&mut w); assert!(v == w); @@ -116,7 +104,7 @@ mod test { #[test] #[should_panic] fn test_reader_rng_insufficient_bytes() { - let mut rng = ReaderRng::new(MemReader::new(vec!())); + let mut rng = ReaderRng::new(&[][..]); let mut v = [0; 3]; rng.fill_bytes(&mut v); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index f71811b1ea..b118010a0c 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -78,7 +78,7 @@ struct Exception { cause: Option>, } -pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: usize); +pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32); // Variables used for invoking callbacks when a thread starts to unwind. // @@ -484,7 +484,7 @@ pub mod eabi { /// Entry point of panic from the libcore crate. #[lang = "panic_fmt"] pub extern fn rust_begin_unwind(msg: fmt::Arguments, - file: &'static str, line: usize) -> ! { + file: &'static str, line: u32) -> ! { begin_unwind_fmt(msg, &(file, line)) } @@ -495,8 +495,7 @@ pub extern fn rust_begin_unwind(msg: fmt::Arguments, /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. #[inline(never)] #[cold] -#[stable(since = "1.0.0", feature = "rust1")] -pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, usize)) -> ! { +pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { use fmt::Write; // We do two allocations here, unfortunately. But (a) they're @@ -511,7 +510,7 @@ pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, usize)) /// This is the entry point of unwinding for panic!() and assert!(). #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible -#[stable(since = "1.0.0", feature = "rust1")] +#[cfg(stage0)] pub fn begin_unwind(msg: M, file_line: &(&'static str, usize)) -> ! { // Note that this should be the only allocation performed in this code path. // Currently this means that panic!() on OOM will invoke this code path, @@ -520,6 +519,22 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, usize)) -> // be performed in the parent of this thread instead of the thread that's // panicking. + // see below for why we do the `Any` coercion here. + let (file, line) = *file_line; + begin_unwind_inner(Box::new(msg), &(file, line as u32)) +} + +/// This is the entry point of unwinding for panic!() and assert!(). +#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible +#[cfg(not(stage0))] +pub fn begin_unwind(msg: M, file_line: &(&'static str, u32)) -> ! { + // Note that this should be the only allocation performed in this code path. + // Currently this means that panic!() on OOM will invoke this code path, + // but then again we're not really ready for panic on OOM anyway. If + // we do start doing this, then we should propagate this allocation to + // be performed in the parent of this thread instead of the thread that's + // panicking. + // see below for why we do the `Any` coercion here. begin_unwind_inner(Box::new(msg), file_line) } @@ -535,7 +550,7 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, usize)) -> /// }` from ~1900/3700 (-O/no opts) to 180/590. #[inline(never)] #[cold] // this is the slow path, please never inline this fn begin_unwind_inner(msg: Box, - file_line: &(&'static str, usize)) -> ! { + file_line: &(&'static str, u32)) -> ! { // Make sure the default failure handler is registered before we look at the // callbacks. We also use a raw sys-based mutex here instead of a // `std::sync` one as accessing TLS can cause weird recursive problems (and @@ -598,7 +613,6 @@ fn begin_unwind_inner(msg: Box, /// Only a limited number of callbacks can be registered, and this function /// returns whether the callback was successfully registered or not. It is not /// currently possible to unregister a callback once it has been registered. -#[unstable(feature = "std_misc")] pub unsafe fn register(f: Callback) -> bool { match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) { // The invocation code has knowledge of this window where the count has diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index ebf4d33774..34fcf6cdad 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -49,7 +49,7 @@ struct BarrierState { pub struct BarrierWaitResult(bool); impl Barrier { - /// Create a new barrier that can block a given number of threads. + /// Creates a new barrier that can block a given number of threads. /// /// A barrier will block `n`-1 threads which call `wait` and then wake up /// all threads at once when the `n`th thread calls `wait`. @@ -65,7 +65,7 @@ impl Barrier { } } - /// Block the current thread until all threads has rendezvoused here. + /// Blocks the current thread until all threads has rendezvoused here. /// /// Barriers are re-usable after all threads have rendezvoused once, and can /// be used continuously. @@ -97,7 +97,7 @@ impl Barrier { } impl BarrierWaitResult { - /// Return whether this thread from `wait` is the "leader thread". + /// Returns whether this thread from `wait` is the "leader thread". /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index a7d8b287a6..c2964b7a4f 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -11,12 +11,12 @@ use prelude::v1::*; use sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; -use sync::poison::{self, LockResult}; -use sys::time::SteadyTime; +use sync::{mutex, MutexGuard, PoisonError}; use sys_common::condvar as sys; use sys_common::mutex as sys_mutex; +use sys_common::poison::{self, LockResult}; +use sys::time::SteadyTime; use time::Duration; -use sync::{mutex, MutexGuard, PoisonError}; /// A Condition Variable /// @@ -102,7 +102,7 @@ impl Condvar { } } - /// Block the current thread until this condition variable receives a + /// Blocks the current thread until this condition variable receives a /// notification. /// /// This function will atomically unlock the mutex specified (represented by @@ -137,7 +137,7 @@ impl Condvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait()` @@ -161,15 +161,7 @@ impl Condvar { } } - /// Deprecated: use `wait_timeout_ms` instead. - #[unstable(feature = "std_misc")] - #[deprecated(since = "1.0.0", reason = "use wait_timeout_ms instead")] - pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) - -> LockResult<(MutexGuard<'a, T>, bool)> { - self.wait_timeout_ms(guard, dur.num_milliseconds() as u32) - } - - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait_timeout` except @@ -189,7 +181,7 @@ impl Condvar { } } - /// Wake up one blocked thread on this condvar. + /// Wakes up one blocked thread on this condvar. /// /// If there is a blocked thread on this condition variable, then it will /// be woken up from its call to `wait` or `wait_timeout`. Calls to @@ -199,7 +191,7 @@ impl Condvar { #[stable(feature = "rust1", since = "1.0.0")] pub fn notify_one(&self) { unsafe { self.inner.inner.notify_one() } } - /// Wake up all blocked threads on this condvar. + /// Wakes up all blocked threads on this condvar. /// /// This method will ensure that any current waiters on the condition /// variable are awoken. Calls to `notify_all()` are not buffered in any @@ -218,7 +210,7 @@ impl Drop for Condvar { } impl StaticCondvar { - /// Block the current thread until this condition variable receives a + /// Blocks the current thread until this condition variable receives a /// notification. /// /// See `Condvar::wait`. @@ -239,7 +231,7 @@ impl StaticCondvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// See `Condvar::wait_timeout`. @@ -260,7 +252,7 @@ impl StaticCondvar { } } - /// Wait on this condition variable for a notification, timing out after a + /// Waits on this condition variable for a notification, timing out after a /// specified duration. /// /// The implementation will repeatedly wait while the duration has not @@ -306,21 +298,21 @@ impl StaticCondvar { poison::map_result(guard_result, |g| (g, true)) } - /// Wake up one blocked thread on this condvar. + /// Wakes up one blocked thread on this condvar. /// /// See `Condvar::notify_one`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] pub fn notify_one(&'static self) { unsafe { self.inner.notify_one() } } - /// Wake up all blocked threads on this condvar. + /// Wakes up all blocked threads on this condvar. /// /// See `Condvar::notify_all`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] pub fn notify_all(&'static self) { unsafe { self.inner.notify_all() } } - /// Deallocate all resources associated with this static condvar. + /// Deallocates all resources associated with this static condvar. /// /// This method is unsafe to call as there is no guarantee that there are no /// active users of the condvar, and this also doesn't prevent any future diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index a5259a0039..91e9714fbe 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -20,15 +20,15 @@ pub use alloc::arc::{Arc, Weak}; pub use core::atomic; -pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; -pub use self::mutex::MUTEX_INIT; -pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; -pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; +pub use self::barrier::{Barrier, BarrierWaitResult}; pub use self::condvar::{Condvar, StaticCondvar, CONDVAR_INIT}; +pub use self::mutex::MUTEX_INIT; +pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; pub use self::once::{Once, ONCE_INIT}; +pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; +pub use self::rwlock::{RwLockReadGuard, RwLockWriteGuard}; +pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT}; pub use self::semaphore::{Semaphore, SemaphoreGuard}; -pub use self::barrier::{Barrier, BarrierWaitResult}; -pub use self::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; pub use self::future::Future; @@ -39,6 +39,5 @@ mod condvar; mod future; mod mutex; mod once; -mod poison; mod rwlock; mod semaphore; diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index c80182ec07..422439fadc 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -112,58 +112,6 @@ //! }); //! rx.recv().unwrap(); //! ``` -//! -//! Reading from a channel with a timeout requires to use a Timer together -//! with the channel. You can use the `select!` macro to select either and -//! handle the timeout case. This first example will break out of the loop -//! after 10 seconds no matter what: -//! -//! ```no_run -//! # #![feature(std_misc, old_io)] -//! use std::sync::mpsc::channel; -//! use std::old_io::timer::Timer; -//! use std::time::Duration; -//! -//! let (tx, rx) = channel::(); -//! let mut timer = Timer::new().unwrap(); -//! let timeout = timer.oneshot(Duration::seconds(10)); -//! -//! loop { -//! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { -//! println!("timed out, total time was more than 10 seconds"); -//! break; -//! } -//! } -//! } -//! ``` -//! -//! This second example is more costly since it allocates a new timer every -//! time a message is received, but it allows you to timeout after the channel -//! has been inactive for 5 seconds: -//! -//! ```no_run -//! # #![feature(std_misc, old_io)] -//! use std::sync::mpsc::channel; -//! use std::old_io::timer::Timer; -//! use std::time::Duration; -//! -//! let (tx, rx) = channel::(); -//! let mut timer = Timer::new().unwrap(); -//! -//! loop { -//! let timeout = timer.oneshot(Duration::seconds(5)); -//! -//! select! { -//! val = rx.recv() => println!("Received {}", val.unwrap()), -//! _ = timeout.recv() => { -//! println!("timed out, no message received in 5 seconds"); -//! break; -//! } -//! } -//! } -//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -397,8 +345,8 @@ pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); #[stable(feature = "rust1", since = "1.0.0")] pub struct RecvError; -/// This enumeration is the list of the possible reasons that try_recv could not -/// return data when called. +/// This enumeration is the list of the possible reasons that `try_recv` could +/// not return data when called. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum TryRecvError { @@ -802,7 +750,7 @@ impl Receiver { } } - /// Attempt to wait for a value on this receiver, returning an error if the + /// Attempts to wait for a value on this receiver, returning an error if the /// corresponding channel has hung up. /// /// This function will always block the current thread if there is no data diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index b509b3472e..b8ad92841f 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -254,11 +254,11 @@ impl Select { } impl<'rx, T: Send> Handle<'rx, T> { - /// Retrieve the id of this handle. + /// Retrieves the id of this handle. #[inline] pub fn id(&self) -> usize { self.id } - /// Block to receive a value on the underlying receiver, returning `Some` on + /// Blocks to receive a value on the underlying receiver, returning `Some` on /// success or `None` if the channel disconnects. This function has the same /// semantics as `Receiver.recv` pub fn recv(&mut self) -> Result { self.rx.recv() } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 16e7f26541..7896870ea0 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -11,11 +11,11 @@ use prelude::v1::*; use cell::UnsafeCell; +use fmt; use marker; use ops::{Deref, DerefMut}; -use sync::poison::{self, TryLockError, TryLockResult, LockResult}; use sys_common::mutex as sys; -use fmt; +use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// A mutual exclusion primitive useful for protecting shared data /// @@ -212,7 +212,7 @@ impl Mutex { /// Attempts to acquire this lock. /// - /// If the lock could not be acquired at this time, then `None` is returned. + /// If the lock could not be acquired at this time, then `Err` is returned. /// Otherwise, an RAII guard is returned. The lock will be unlocked when the /// guard is dropped. /// @@ -232,7 +232,7 @@ impl Mutex { } } - /// Determine whether the lock is poisoned. + /// Determines whether the lock is poisoned. /// /// If another thread is active, the lock can still become poisoned at any /// time. You should not trust a `false` value for program correctness diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 258cf1d38a..948965f5ef 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -51,7 +51,7 @@ pub const ONCE_INIT: Once = Once { }; impl Once { - /// Perform an initialization routine once and only once. The given closure + /// Performs an initialization routine once and only once. The given closure /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. /// diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index d70350bc7d..1ea92d5eff 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -11,11 +11,11 @@ use prelude::v1::*; use cell::UnsafeCell; +use fmt; use marker; use ops::{Deref, DerefMut}; -use sync::poison::{self, LockResult, TryLockError, TryLockResult}; +use sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; use sys_common::rwlock as sys; -use fmt; /// A reader-writer lock /// @@ -169,7 +169,7 @@ impl RwLock { RwLockReadGuard::new(&*self.inner, &self.data) } - /// Attempt to acquire this lock with shared read access. + /// Attempts to acquire this lock with shared read access. /// /// This function will never block and will return immediately if `read` /// would otherwise succeed. Returns `Some` of an RAII guard which will @@ -194,7 +194,7 @@ impl RwLock { } } - /// Lock this rwlock with exclusive write access, blocking the current + /// Locks this rwlock with exclusive write access, blocking the current /// thread until it can be acquired. /// /// This function will not return while other writers or other readers @@ -215,7 +215,7 @@ impl RwLock { RwLockWriteGuard::new(&*self.inner, &self.data) } - /// Attempt to lock this rwlock with exclusive write access. + /// Attempts to lock this rwlock with exclusive write access. /// /// This function does not ever block, and it will return `None` if a call /// to `write` would otherwise block. If successful, an RAII guard is @@ -237,7 +237,7 @@ impl RwLock { } } - /// Determine whether the lock is poisoned. + /// Determines whether the lock is poisoned. /// /// If another thread is active, the lock can still become poisoned at any /// time. You should not trust a `false` value for program correctness @@ -287,7 +287,7 @@ impl StaticRwLock { RwLockReadGuard::new(self, &DUMMY.0) } - /// Attempt to acquire this lock with shared read access. + /// Attempts to acquire this lock with shared read access. /// /// See `RwLock::try_read`. #[inline] @@ -302,7 +302,7 @@ impl StaticRwLock { } } - /// Lock this rwlock with exclusive write access, blocking the current + /// Locks this rwlock with exclusive write access, blocking the current /// thread until it can be acquired. /// /// See `RwLock::write`. @@ -314,7 +314,7 @@ impl StaticRwLock { RwLockWriteGuard::new(self, &DUMMY.0) } - /// Attempt to lock this rwlock with exclusive write access. + /// Attempts to lock this rwlock with exclusive write access. /// /// See `RwLock::try_write`. #[inline] @@ -329,7 +329,7 @@ impl StaticRwLock { } } - /// Deallocate all resources associated with this static lock. + /// Deallocates all resources associated with this static lock. /// /// This method is unsafe to call as there is no guarantee that there are no /// active users of the lock, and this also doesn't prevent any future users diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index cd118b3c9e..580d970af0 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -76,7 +76,7 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { try!(writer.write_all(s.as_bytes())); } else { let mut first = true; - while inner.len() > 0 { + while !inner.is_empty() { if !first { try!(writer.write_all(b"::")); } else { @@ -89,7 +89,7 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); inner = &rest[i..]; rest = &rest[..i]; - while rest.len() > 0 { + while !rest.is_empty() { if rest.starts_with("$") { macro_rules! demangle { ($($pat:expr, => $demangled:expr),*) => ({ diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys/common/condvar.rs index 32fa6ec590..9f46b0c382 100644 --- a/src/libstd/sys/common/condvar.rs +++ b/src/libstd/sys/common/condvar.rs @@ -31,15 +31,15 @@ impl Condvar { #[inline] pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) } - /// Signal one waiter on this condition variable to wake up. + /// Signals one waiter on this condition variable to wake up. #[inline] pub unsafe fn notify_one(&self) { self.0.notify_one() } - /// Awaken all current waiters on this condition variable. + /// Awakens all current waiters on this condition variable. #[inline] pub unsafe fn notify_all(&self) { self.0.notify_all() } - /// Wait for a signal on the specified mutex. + /// Waits for a signal on the specified mutex. /// /// Behavior is undefined if the mutex is not locked by the current thread. /// Behavior is also undefined if more than one mutex is used concurrently @@ -47,7 +47,7 @@ impl Condvar { #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { self.0.wait(mutex::raw(mutex)) } - /// Wait for a signal on the specified mutex with a timeout duration + /// Waits for a signal on the specified mutex with a timeout duration /// specified by `dur` (a relative time into the future). /// /// Behavior is undefined if the mutex is not locked by the current thread. @@ -58,7 +58,7 @@ impl Condvar { self.0.wait_timeout(mutex::raw(mutex), dur) } - /// Deallocate all resources associated with this condition variable. + /// Deallocates all resources associated with this condition variable. /// /// Behavior is undefined if there are current or will be future users of /// this condition variable. diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index d2e2f1044d..95294b813e 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -10,25 +10,14 @@ #![allow(missing_docs)] -use old_io::{self, IoError, IoResult}; use prelude::v1::*; -use sys::{last_error, retry}; -use ffi::CString; -#[allow(deprecated)] // Int -use num::Int; - -#[allow(deprecated)] -use old_path::BytesContainer; - -use collections; - -#[macro_use] pub mod helper_thread; pub mod backtrace; pub mod condvar; pub mod mutex; -pub mod net; pub mod net2; +pub mod poison; +pub mod remutex; pub mod rwlock; pub mod stack; pub mod thread; @@ -38,72 +27,6 @@ pub mod wtf8; // common error constructors -#[allow(deprecated)] -pub fn eof() -> IoError { - IoError { - kind: old_io::EndOfFile, - desc: "end of file", - detail: None, - } -} - -#[allow(deprecated)] -pub fn timeout(desc: &'static str) -> IoError { - IoError { - kind: old_io::TimedOut, - desc: desc, - detail: None, - } -} - -#[allow(deprecated)] -pub fn short_write(n: usize, desc: &'static str) -> IoError { - IoError { - kind: if n == 0 { old_io::TimedOut } else { old_io::ShortWrite(n) }, - desc: desc, - detail: None, - } -} - -#[allow(deprecated)] -pub fn unimpl() -> IoError { - IoError { - kind: old_io::IoUnavailable, - desc: "operations not yet supported", - detail: None, - } -} - -// unix has nonzero values as errors -#[allow(deprecated)] -pub fn mkerr_libc(ret: T) -> IoResult<()> { - if ret != Int::zero() { - Err(last_error()) - } else { - Ok(()) - } -} - -pub fn keep_going(data: &[u8], mut f: F) -> i64 where - F: FnMut(*const u8, usize) -> i64, -{ - let origamt = data.len(); - let mut data = data.as_ptr(); - let mut amt = origamt; - while amt > 0 { - let ret = retry(|| f(data, amt)); - if ret == 0 { - break - } else if ret != -1 { - amt -= ret as usize; - data = unsafe { data.offset(ret as isize) }; - } else { - return ret; - } - } - return (origamt - amt) as i64; -} - /// A trait for viewing representations from std types #[doc(hidden)] pub trait AsInner { @@ -127,15 +50,3 @@ pub trait IntoInner { pub trait FromInner { fn from_inner(inner: Inner) -> Self; } - -#[doc(hidden)] -#[allow(deprecated)] -pub trait ProcessConfig { - fn program(&self) -> &CString; - fn args(&self) -> &[CString]; - fn env(&self) -> Option<&collections::HashMap>; - fn cwd(&self) -> Option<&CString>; - fn uid(&self) -> Option; - fn gid(&self) -> Option; - fn detach(&self) -> bool; -} diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 0ca2282670..1f9dd54192 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -24,14 +24,14 @@ unsafe impl Sync for Mutex {} pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT); impl Mutex { - /// Lock the mutex blocking the current thread until it is available. + /// Locks the mutex blocking the current thread until it is available. /// /// Behavior is undefined if the mutex has been moved between this and any /// previous function call. #[inline] pub unsafe fn lock(&self) { self.0.lock() } - /// Attempt to lock the mutex without blocking, returning whether it was + /// Attempts to lock the mutex without blocking, returning whether it was /// successfully acquired or not. /// /// Behavior is undefined if the mutex has been moved between this and any @@ -39,14 +39,14 @@ impl Mutex { #[inline] pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() } - /// Unlock the mutex. + /// Unlocks the mutex. /// /// Behavior is undefined if the current thread does not actually hold the /// mutex. #[inline] pub unsafe fn unlock(&self) { self.0.unlock() } - /// Deallocate all resources associated with this mutex. + /// Deallocates all resources associated with this mutex. /// /// Behavior is undefined if there are current or will be future users of /// this mutex. diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs deleted file mode 100644 index fc21effb45..0000000000 --- a/src/libstd/sys/common/net.rs +++ /dev/null @@ -1,971 +0,0 @@ -// Copyright 2013-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. - -#![allow(deprecated)] - -use prelude::v1::*; -use self::SocketStatus::*; -use self::InAddr::*; - -use ffi::{CString, CStr}; -use old_io::net::addrinfo; -use old_io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; -use old_io::{IoResult, IoError}; -use libc::{self, c_char, c_int}; -use mem; -use num::Int; -use ptr::{self, null, null_mut}; -use str; -use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, - wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, - decode_error_detailed}; -use sync::{Arc, Mutex}; -#[cfg(not(target_os = "linux"))] -use sync::MutexGuard; -use sys_common::{self, keep_going, short_write, timeout}; -use cmp; -use old_io; - -// FIXME: move uses of Arc and deadline tracking to std::io - -#[derive(Debug)] -pub enum SocketStatus { - Readable, - Writable, -} - -//////////////////////////////////////////////////////////////////////////////// -// sockaddr and misc bindings -//////////////////////////////////////////////////////////////////////////////// - -pub fn htons(u: u16) -> u16 { - u.to_be() -} -pub fn ntohs(u: u16) -> u16 { - Int::from_be(u) -} - -pub enum InAddr { - In4Addr(libc::in_addr), - In6Addr(libc::in6_addr), -} - -pub fn ip_to_inaddr(ip: IpAddr) -> InAddr { - match ip { - Ipv4Addr(a, b, c, d) => { - let ip = ((a as u32) << 24) | - ((b as u32) << 16) | - ((c as u32) << 8) | - ((d as u32) << 0); - In4Addr(libc::in_addr { - s_addr: Int::from_be(ip) - }) - } - Ipv6Addr(a, b, c, d, e, f, g, h) => { - In6Addr(libc::in6_addr { - s6_addr: [ - htons(a), - htons(b), - htons(c), - htons(d), - htons(e), - htons(f), - htons(g), - htons(h), - ] - }) - } - } -} - -pub fn addr_to_sockaddr(addr: SocketAddr, - storage: &mut libc::sockaddr_storage) - -> libc::socklen_t { - unsafe { - let len = match ip_to_inaddr(addr.ip) { - In4Addr(inaddr) => { - let storage = storage as *mut _ as *mut libc::sockaddr_in; - (*storage).sin_family = libc::AF_INET as libc::sa_family_t; - (*storage).sin_port = htons(addr.port); - (*storage).sin_addr = inaddr; - mem::size_of::() - } - In6Addr(inaddr) => { - let storage = storage as *mut _ as *mut libc::sockaddr_in6; - (*storage).sin6_family = libc::AF_INET6 as libc::sa_family_t; - (*storage).sin6_port = htons(addr.port); - (*storage).sin6_addr = inaddr; - mem::size_of::() - } - }; - return len as libc::socklen_t; - } -} - -pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult { - unsafe { - let fam = match addr.ip { - Ipv4Addr(..) => libc::AF_INET, - Ipv6Addr(..) => libc::AF_INET6, - }; - match libc::socket(fam, ty, 0) as i32 { - -1 => Err(last_net_error()), - fd => Ok(fd as sock_t), - } - } -} - -pub fn setsockopt(fd: sock_t, opt: libc::c_int, val: libc::c_int, - payload: T) -> IoResult<()> { - unsafe { - let payload = &payload as *const T as *const libc::c_void; - let ret = libc::setsockopt(fd, opt, val, - payload, - mem::size_of::() as libc::socklen_t); - if ret != 0 { - Err(last_net_error()) - } else { - Ok(()) - } - } -} - -pub fn getsockopt(fd: sock_t, opt: libc::c_int, - val: libc::c_int) -> IoResult { - unsafe { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - let ret = c::getsockopt(fd, opt, val, - &mut slot as *mut _ as *mut _, - &mut len); - if ret != 0 { - Err(last_net_error()) - } else { - assert!(len as usize == mem::size_of::()); - Ok(slot) - } - } -} - -pub fn sockname(fd: sock_t, - f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr, - *mut libc::socklen_t) -> libc::c_int) - -> IoResult -{ - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut len = mem::size_of::() as libc::socklen_t; - unsafe { - let storage = &mut storage as *mut libc::sockaddr_storage; - let ret = f(fd, - storage as *mut libc::sockaddr, - &mut len as *mut libc::socklen_t); - if ret != 0 { - return Err(last_net_error()) - } - } - return sockaddr_to_addr(&storage, len as usize); -} - -pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: usize) -> IoResult { - match storage.ss_family as libc::c_int { - libc::AF_INET => { - assert!(len as usize >= mem::size_of::()); - let storage: &libc::sockaddr_in = unsafe { - mem::transmute(storage) - }; - let ip = (storage.sin_addr.s_addr as u32).to_be(); - let a = (ip >> 24) as u8; - let b = (ip >> 16) as u8; - let c = (ip >> 8) as u8; - let d = (ip >> 0) as u8; - Ok(SocketAddr { - ip: Ipv4Addr(a, b, c, d), - port: ntohs(storage.sin_port), - }) - } - libc::AF_INET6 => { - assert!(len as usize >= mem::size_of::()); - let storage: &libc::sockaddr_in6 = unsafe { - mem::transmute(storage) - }; - let a = ntohs(storage.sin6_addr.s6_addr[0]); - let b = ntohs(storage.sin6_addr.s6_addr[1]); - let c = ntohs(storage.sin6_addr.s6_addr[2]); - let d = ntohs(storage.sin6_addr.s6_addr[3]); - let e = ntohs(storage.sin6_addr.s6_addr[4]); - let f = ntohs(storage.sin6_addr.s6_addr[5]); - let g = ntohs(storage.sin6_addr.s6_addr[6]); - let h = ntohs(storage.sin6_addr.s6_addr[7]); - Ok(SocketAddr { - ip: Ipv6Addr(a, b, c, d, e, f, g, h), - port: ntohs(storage.sin6_port), - }) - } - _ => { - Err(IoError { - kind: old_io::InvalidInput, - desc: "invalid argument", - detail: None, - }) - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// get_host_addresses -//////////////////////////////////////////////////////////////////////////////// - -extern "system" { - fn getaddrinfo(node: *const c_char, service: *const c_char, - hints: *const libc::addrinfo, - res: *mut *mut libc::addrinfo) -> c_int; - fn freeaddrinfo(res: *mut libc::addrinfo); -} - -pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, - hint: Option) - -> Result, IoError> -{ - sys::init_net(); - - assert!(host.is_some() || servname.is_some()); - - let c_host = match host { - Some(x) => Some(try!(CString::new(x))), - None => None, - }; - let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = match servname { - Some(x) => Some(try!(CString::new(x))), - None => None, - }; - let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - - let hint = hint.map(|hint| { - libc::addrinfo { - ai_flags: hint.flags as c_int, - ai_family: hint.family as c_int, - ai_socktype: 0, - ai_protocol: 0, - ai_addrlen: 0, - ai_canonname: null_mut(), - ai_addr: null_mut(), - ai_next: null_mut() - } - }); - - let hint_ptr = hint.as_ref().map_or(null(), |x| { - x as *const libc::addrinfo - }); - let mut res = null_mut(); - - // Make the call - let s = unsafe { - getaddrinfo(c_host, c_serv, hint_ptr, &mut res) - }; - - // Error? - if s != 0 { - return Err(last_gai_error(s)); - } - - // Collect all the results we found - let mut addrs = Vec::new(); - let mut rp = res; - while !rp.is_null() { - unsafe { - let addr = try!(sockaddr_to_addr(mem::transmute((*rp).ai_addr), - (*rp).ai_addrlen as usize)); - addrs.push(addrinfo::Info { - address: addr, - family: (*rp).ai_family as usize, - socktype: None, - protocol: None, - flags: (*rp).ai_flags as usize - }); - - rp = (*rp).ai_next as *mut libc::addrinfo; - } - } - - unsafe { freeaddrinfo(res); } - - Ok(addrs) -} - -//////////////////////////////////////////////////////////////////////////////// -// get_address_name -//////////////////////////////////////////////////////////////////////////////// - -extern "system" { - fn getnameinfo(sa: *const libc::sockaddr, salen: libc::socklen_t, - host: *mut c_char, hostlen: libc::size_t, - serv: *mut c_char, servlen: libc::size_t, - flags: c_int) -> c_int; -} - -const NI_MAXHOST: usize = 1025; - -pub fn get_address_name(addr: IpAddr) -> Result { - let addr = SocketAddr{ip: addr, port: 0}; - - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let len = addr_to_sockaddr(addr, &mut storage); - - let mut hostbuf = [0 as c_char; NI_MAXHOST]; - - let res = unsafe { - getnameinfo(&storage as *const _ as *const libc::sockaddr, len, - hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t, - ptr::null_mut(), 0, - 0) - }; - - if res != 0 { - return Err(last_gai_error(res)); - } - - unsafe { - let data = CStr::from_ptr(hostbuf.as_ptr()); - Ok(str::from_utf8(data.to_bytes()).unwrap().to_string()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Timeout helpers -// -// The read/write functions below are the helpers for reading/writing a socket -// with a possible deadline specified. This is generally viewed as a timed out -// I/O operation. -// -// From the application's perspective, timeouts apply to the I/O object, not to -// the underlying file descriptor (it's one timeout per object). This means that -// we can't use the SO_RCVTIMEO and corresponding send timeout option. -// -// The next idea to implement timeouts would be to use nonblocking I/O. An -// invocation of select() would wait (with a timeout) for a socket to be ready. -// Once its ready, we can perform the operation. Note that the operation *must* -// be nonblocking, even though select() says the socket is ready. This is -// because some other thread could have come and stolen our data (handles can be -// cloned). -// -// To implement nonblocking I/O, the first option we have is to use the -// O_NONBLOCK flag. Remember though that this is a global setting, affecting all -// I/O objects, so this was initially viewed as unwise. -// -// It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to -// send/recv, but the niftiness wears off once you realize it only works well on -// Linux [1] [2]. This means that it's pretty easy to get a nonblocking -// operation on Linux (no flag fiddling, no affecting other objects), but not on -// other platforms. -// -// To work around this constraint on other platforms, we end up using the -// original strategy of flipping the O_NONBLOCK flag. As mentioned before, this -// could cause other objects' blocking operations to suddenly become -// nonblocking. To get around this, a "blocking operation" which returns EAGAIN -// falls back to using the same code path as nonblocking operations, but with an -// infinite timeout (select + send/recv). This helps emulate blocking -// reads/writes despite the underlying descriptor being nonblocking, as well as -// optimizing the fast path of just hitting one syscall in the good case. -// -// As a final caveat, this implementation uses a mutex so only one thread is -// doing a nonblocking operation at at time. This is the operation that comes -// after the select() (at which point we think the socket is ready). This is -// done for sanity to ensure that the state of the O_NONBLOCK flag is what we -// expect (wouldn't want someone turning it on when it should be off!). All -// operations performed in the lock are *nonblocking* to avoid holding the mutex -// forever. -// -// So, in summary, Linux uses MSG_DONTWAIT and doesn't need mutexes, everyone -// else uses O_NONBLOCK and mutexes with some trickery to make sure blocking -// reads/writes are still blocking. -// -// Fun, fun! -// -// [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html -// [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait - -pub fn read(fd: sock_t, deadline: u64, mut lock: L, mut read: R) -> IoResult where - L: FnMut() -> T, - R: FnMut(bool) -> libc::c_int, -{ - let mut ret = -1; - if deadline == 0 { - ret = retry(|| read(false)); - } - - if deadline != 0 || (ret == -1 && wouldblock()) { - let deadline = match deadline { - 0 => None, - n => Some(n), - }; - loop { - // With a timeout, first we wait for the socket to become - // readable using select(), specifying the relevant timeout for - // our previously set deadline. - try!(await(&[fd], deadline, Readable)); - - // At this point, we're still within the timeout, and we've - // determined that the socket is readable (as returned by - // select). We must still read the socket in *nonblocking* mode - // because some other thread could come steal our data. If we - // fail to read some data, we retry (hence the outer loop) and - // wait for the socket to become readable again. - let _guard = lock(); - match retry(|| read(deadline.is_some())) { - -1 if wouldblock() => {} - -1 => return Err(last_net_error()), - n => { ret = n; break } - } - } - } - - match ret { - 0 => Err(sys_common::eof()), - n if n < 0 => Err(last_net_error()), - n => Ok(n as usize) - } -} - -pub fn write(fd: sock_t, - deadline: u64, - buf: &[u8], - write_everything: bool, - mut lock: L, - mut write: W) -> IoResult where - L: FnMut() -> T, - W: FnMut(bool, *const u8, usize) -> i64, -{ - let mut ret = -1; - let mut written = 0; - if deadline == 0 { - if write_everything { - ret = keep_going(buf, |inner, len| { - written = buf.len() - len; - write(false, inner, len) - }); - } else { - ret = retry(|| { write(false, buf.as_ptr(), buf.len()) }); - if ret > 0 { written = ret as usize; } - } - } - - if deadline != 0 || (ret == -1 && wouldblock()) { - let deadline = match deadline { - 0 => None, - n => Some(n), - }; - while written < buf.len() && (write_everything || written == 0) { - // As with read(), first wait for the socket to be ready for - // the I/O operation. - match await(&[fd], deadline, Writable) { - Err(ref e) if e.kind == old_io::EndOfFile && written > 0 => { - assert!(deadline.is_some()); - return Err(short_write(written, "short write")) - } - Err(e) => return Err(e), - Ok(()) => {} - } - - // Also as with read(), we use MSG_DONTWAIT to guard ourselves - // against unforeseen circumstances. - let _guard = lock(); - let ptr = buf[written..].as_ptr(); - let len = buf.len() - written; - match retry(|| write(deadline.is_some(), ptr, len)) { - -1 if wouldblock() => {} - -1 => return Err(last_net_error()), - n => { written += n as usize; } - } - } - ret = 0; - } - if ret < 0 { - Err(last_net_error()) - } else { - Ok(written) - } -} - -// See http://developerweb.net/viewtopic.php?id=3196 for where this is -// derived from. -pub fn connect_timeout(fd: sock_t, - addrp: *const libc::sockaddr, - len: libc::socklen_t, - timeout_ms: u64) -> IoResult<()> { - #[cfg(unix)] use libc::EINPROGRESS as INPROGRESS; - #[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS; - #[cfg(unix)] use libc::EWOULDBLOCK as WOULDBLOCK; - #[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK; - - // Make sure the call to connect() doesn't block - set_nonblocking(fd, true); - - let ret = match unsafe { libc::connect(fd, addrp, len) } { - // If the connection is in progress, then we need to wait for it to - // finish (with a timeout). The current strategy for doing this is - // to use select() with a timeout. - -1 if os::errno() as isize == INPROGRESS as isize || - os::errno() as isize == WOULDBLOCK as isize => { - let mut set: c::fd_set = unsafe { mem::zeroed() }; - c::fd_set(&mut set, fd); - match await(fd, &mut set, timeout_ms) { - 0 => Err(timeout("connection timed out")), - -1 => Err(last_net_error()), - _ => { - let err: libc::c_int = try!( - getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR)); - if err == 0 { - Ok(()) - } else { - Err(decode_error_detailed(err)) - } - } - } - } - - -1 => Err(last_net_error()), - _ => Ok(()), - }; - - // be sure to turn blocking I/O back on - set_nonblocking(fd, false); - return ret; - - #[cfg(unix)] - fn await(fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int { - let start = timer::now(); - retry(|| unsafe { - // Recalculate the timeout each iteration (it is generally - // undefined what the value of the 'tv' is after select - // returns EINTR). - let mut tv = ms_to_timeval(timeout - (timer::now() - start)); - c::select(fd + 1, ptr::null_mut(), set as *mut _, - ptr::null_mut(), &mut tv) - }) - } - #[cfg(windows)] - fn await(_fd: sock_t, set: &mut c::fd_set, timeout: u64) -> libc::c_int { - let mut tv = ms_to_timeval(timeout); - unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) } - } -} - -pub fn await(fds: &[sock_t], deadline: Option, - status: SocketStatus) -> IoResult<()> { - let mut set: c::fd_set = unsafe { mem::zeroed() }; - let mut max = 0; - for &fd in fds { - c::fd_set(&mut set, fd); - max = cmp::max(max, fd + 1); - } - if cfg!(windows) { - max = fds.len() as sock_t; - } - - let (read, write) = match status { - Readable => (&mut set as *mut _, ptr::null_mut()), - Writable => (ptr::null_mut(), &mut set as *mut _), - }; - let mut tv: libc::timeval = unsafe { mem::zeroed() }; - - match retry(|| { - let now = timer::now(); - let tvp = match deadline { - None => ptr::null_mut(), - Some(deadline) => { - // If we're past the deadline, then pass a 0 timeout to - // select() so we can poll the status - let ms = if deadline < now {0} else {deadline - now}; - tv = ms_to_timeval(ms); - &mut tv as *mut _ - } - }; - let r = unsafe { - c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp) - }; - r - }) { - -1 => Err(last_net_error()), - 0 => Err(timeout("timed out")), - _ => Ok(()), - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Basic socket representation -//////////////////////////////////////////////////////////////////////////////// - -struct Inner { - fd: sock_t, - - // Unused on Linux, where this lock is not necessary. - #[allow(dead_code)] - lock: Mutex<()>, -} - -impl Inner { - fn new(fd: sock_t) -> Inner { - Inner { fd: fd, lock: Mutex::new(()) } - } -} - -impl Drop for Inner { - fn drop(&mut self) { unsafe { close_sock(self.fd); } } -} - -#[cfg(not(target_os = "linux"))] -pub struct Guard<'a> { - pub fd: sock_t, - pub guard: MutexGuard<'a, ()>, -} - -#[cfg(not(target_os = "linux"))] -#[unsafe_destructor] -impl<'a> Drop for Guard<'a> { - fn drop(&mut self) { - set_nonblocking(self.fd, false); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpStream { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl TcpStream { - pub fn connect(addr: SocketAddr, timeout: Option) -> IoResult { - sys::init_net(); - - let fd = try!(socket(addr, libc::SOCK_STREAM)); - let ret = TcpStream::new(fd); - - let mut storage = unsafe { mem::zeroed() }; - let len = addr_to_sockaddr(addr, &mut storage); - let addrp = &storage as *const _ as *const libc::sockaddr; - - match timeout { - Some(timeout) => { - try!(connect_timeout(fd, addrp, len, timeout)); - Ok(ret) - }, - None => { - match retry(|| unsafe { libc::connect(fd, addrp, len) }) { - -1 => Err(last_error()), - _ => Ok(ret), - } - } - } - } - - pub fn new(fd: sock_t) -> TcpStream { - TcpStream { - inner: Arc::new(Inner::new(fd)), - read_deadline: 0, - write_deadline: 0, - } - } - - pub fn fd(&self) -> sock_t { self.inner.fd } - - pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_NODELAY, - nodelay as libc::c_int) - } - - pub fn set_keepalive(&mut self, seconds: Option) -> IoResult<()> { - let ret = setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_KEEPALIVE, - seconds.is_some() as libc::c_int); - match seconds { - Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)), - None => ret, - } - } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn set_tcp_keepalive(&mut self, seconds: usize) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, - seconds as libc::c_int) - } - #[cfg(any(target_os = "freebsd", - target_os = "dragonfly"))] - fn set_tcp_keepalive(&mut self, seconds: usize) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, - seconds as libc::c_int) - } - #[cfg(target_os = "openbsd")] - fn set_tcp_keepalive(&mut self, seconds: usize) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_TCP, libc::SO_KEEPALIVE, - seconds as libc::c_int) - } - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd")))] - fn set_tcp_keepalive(&mut self, _seconds: usize) -> IoResult<()> { - Ok(()) - } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) {} - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { - let ret = Guard { - fd: self.fd(), - guard: self.inner.lock.lock().unwrap(), - }; - set_nonblocking(self.fd(), true); - ret - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let doread = |nb| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::recv(fd, - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as wrlen, - flags) as libc::c_int - }; - read(fd, self.read_deadline, dolock, doread) - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let dowrite = |nb: bool, buf: *const u8, len: usize| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::send(fd, - buf as *const _, - len as wrlen, - flags) as i64 - }; - write(fd, self.write_deadline, buf, true, dolock, dowrite).map(|_| ()) - } - pub fn peer_name(&mut self) -> IoResult { - sockname(self.fd(), libc::getpeername) - } - - pub fn close_write(&mut self) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) }) - } - pub fn close_read(&mut self) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) }) - } - - pub fn set_timeout(&mut self, timeout: Option) { - let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - self.read_deadline = deadline; - self.write_deadline = deadline; - } - pub fn set_read_timeout(&mut self, timeout: Option) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - pub fn set_write_timeout(&mut self, timeout: Option) { - self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn socket_name(&mut self) -> IoResult { - sockname(self.fd(), libc::getsockname) - } -} - -impl Clone for TcpStream { - fn clone(&self) -> TcpStream { - TcpStream { - inner: self.inner.clone(), - read_deadline: 0, - write_deadline: 0, - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// UDP -//////////////////////////////////////////////////////////////////////////////// - -pub struct UdpSocket { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl UdpSocket { - pub fn bind(addr: SocketAddr) -> IoResult { - sys::init_net(); - - let fd = try!(socket(addr, libc::SOCK_DGRAM)); - let ret = UdpSocket { - inner: Arc::new(Inner::new(fd)), - read_deadline: 0, - write_deadline: 0, - }; - - let mut storage = unsafe { mem::zeroed() }; - let len = addr_to_sockaddr(addr, &mut storage); - let addrp = &storage as *const _ as *const libc::sockaddr; - - match unsafe { libc::bind(fd, addrp, len) } { - -1 => Err(last_error()), - _ => Ok(ret), - } - } - - pub fn fd(&self) -> sock_t { self.inner.fd } - - pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> { - setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_BROADCAST, - on as libc::c_int) - } - - pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, - on as libc::c_int) - } - - pub fn set_membership(&mut self, addr: IpAddr, opt: libc::c_int) -> IoResult<()> { - match ip_to_inaddr(addr) { - In4Addr(addr) => { - let mreq = libc::ip_mreq { - imr_multiaddr: addr, - // interface == INADDR_ANY - imr_interface: libc::in_addr { s_addr: 0x0 }, - }; - setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq) - } - In6Addr(addr) => { - let mreq = libc::ip6_mreq { - ipv6mr_multiaddr: addr, - ipv6mr_interface: 0, - }; - setsockopt(self.fd(), libc::IPPROTO_IPV6, opt, mreq) - } - } - } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) {} - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { - let ret = Guard { - fd: self.fd(), - guard: self.inner.lock.lock().unwrap(), - }; - set_nonblocking(self.fd(), true); - ret - } - - pub fn socket_name(&mut self) -> IoResult { - sockname(self.fd(), libc::getsockname) - } - - pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(usize, SocketAddr)> { - let fd = self.fd(); - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let storagep = &mut storage as *mut _ as *mut libc::sockaddr; - let mut addrlen: libc::socklen_t = - mem::size_of::() as libc::socklen_t; - - let dolock = || self.lock_nonblocking(); - let n = try!(read(fd, self.read_deadline, dolock, |nb| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::recvfrom(fd, - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as msglen_t, - flags, - storagep, - &mut addrlen) as libc::c_int - })); - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize).unwrap())) - } - - pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { - let mut storage = unsafe { mem::zeroed() }; - let dstlen = addr_to_sockaddr(dst, &mut storage); - let dstp = &storage as *const _ as *const libc::sockaddr; - - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let dowrite = |nb, buf: *const u8, len: usize| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::sendto(fd, - buf as *const libc::c_void, - len as msglen_t, - flags, - dstp, - dstlen) as i64 - }; - - let n = try!(write(fd, self.write_deadline, buf, false, dolock, dowrite)); - assert!(n == buf.len(), "UDP packet not completely written."); - Ok(()) - } - - pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - match multi { - Ipv4Addr(..) => { - self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) - } - Ipv6Addr(..) => { - self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) - } - } - } - pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { - match multi { - Ipv4Addr(..) => { - self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) - } - Ipv6Addr(..) => { - self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) - } - } - } - - pub fn multicast_time_to_live(&mut self, ttl: isize) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, - ttl as libc::c_int) - } - pub fn time_to_live(&mut self, ttl: isize) -> IoResult<()> { - setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int) - } - - pub fn set_timeout(&mut self, timeout: Option) { - let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - self.read_deadline = deadline; - self.write_deadline = deadline; - } - pub fn set_read_timeout(&mut self, timeout: Option) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - pub fn set_write_timeout(&mut self, timeout: Option) { - self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } -} - -impl Clone for UdpSocket { - fn clone(&self) -> UdpSocket { - UdpSocket { - inner: self.inner.clone(), - read_deadline: 0, - write_deadline: 0, - } - } -} diff --git a/src/libstd/sync/poison.rs b/src/libstd/sys/common/poison.rs similarity index 99% rename from src/libstd/sync/poison.rs rename to src/libstd/sys/common/poison.rs index 347cd0b464..6deb4a4800 100644 --- a/src/libstd/sync/poison.rs +++ b/src/libstd/sys/common/poison.rs @@ -116,7 +116,7 @@ impl Error for PoisonError { } impl PoisonError { - /// Create a `PoisonError`. + /// Creates a `PoisonError`. #[unstable(feature = "std_misc")] pub fn new(guard: T) -> PoisonError { PoisonError { guard: guard } diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys/common/remutex.rs new file mode 100644 index 0000000000..b35063c0e2 --- /dev/null +++ b/src/libstd/sys/common/remutex.rs @@ -0,0 +1,233 @@ +// 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. +#![unstable(feature = "reentrant_mutex", reason = "new API")] + +use prelude::v1::*; + +use fmt; +use marker; +use ops::Deref; +use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; +use sys::mutex as sys; + +/// A re-entrant mutual exclusion +/// +/// This mutex will block *other* threads waiting for the lock to become available. The thread +/// which has already locked the mutex can lock it multiple times without blocking, preventing a +/// common source of deadlocks. +pub struct ReentrantMutex { + inner: Box, + poison: poison::Flag, + data: T, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + + +/// An RAII implementation of a "scoped lock" of a mutex. When this structure is +/// dropped (falls out of scope), the lock will be unlocked. +/// +/// The data protected by the mutex can be accessed through this guard via its +/// Deref and DerefMut implementations +#[must_use] +pub struct ReentrantMutexGuard<'a, T: 'a> { + // funny underscores due to how Deref/DerefMut currently work (they + // disregard field privacy). + __lock: &'a ReentrantMutex, + __poison: poison::Guard, +} + +impl<'a, T> !marker::Send for ReentrantMutexGuard<'a, T> {} + + +impl ReentrantMutex { + /// Creates a new reentrant mutex in an unlocked state. + pub fn new(t: T) -> ReentrantMutex { + ReentrantMutex { + inner: box unsafe { sys::ReentrantMutex::new() }, + poison: poison::FLAG_INIT, + data: t, + } + } + + /// Acquires a mutex, blocking the current thread until it is able to do so. + /// + /// This function will block the caller until it is available to acquire the mutex. + /// Upon returning, the thread is the only thread with the mutex held. When the thread + /// calling this method already holds the lock, the call shall succeed without + /// blocking. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return failure if the mutex would otherwise be + /// acquired. + pub fn lock(&self) -> LockResult> { + unsafe { self.inner.lock() } + ReentrantMutexGuard::new(&self) + } + + /// Attempts to acquire this lock. + /// + /// If the lock could not be acquired at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned. + /// + /// This function does not block. + /// + /// # Failure + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return failure if the mutex would otherwise be + /// acquired. + pub fn try_lock(&self) -> TryLockResult> { + if unsafe { self.inner.try_lock() } { + Ok(try!(ReentrantMutexGuard::new(&self))) + } else { + Err(TryLockError::WouldBlock) + } + } +} + +#[unsafe_destructor] +impl Drop for ReentrantMutex { + fn drop(&mut self) { + // This is actually safe b/c we know that there is no further usage of + // this mutex (it's up to the user to arrange for a mutex to get + // dropped, that's not our job) + unsafe { self.inner.destroy() } + } +} + +impl fmt::Debug for ReentrantMutex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.try_lock() { + Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard), + Err(TryLockError::Poisoned(err)) => { + write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + }, + Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ }}") + } + } +} + +impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { + fn new(lock: &'mutex ReentrantMutex) + -> LockResult> { + poison::map_result(lock.poison.borrow(), |guard| { + ReentrantMutexGuard { + __lock: lock, + __poison: guard, + } + }) + } +} + +impl<'mutex, T> Deref for ReentrantMutexGuard<'mutex, T> { + type Target = T; + + fn deref<'a>(&'a self) -> &'a T { + &self.__lock.data + } +} + +#[unsafe_destructor] +impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { + #[inline] + fn drop(&mut self) { + unsafe { + self.__lock.poison.done(&self.__poison); + self.__lock.inner.unlock(); + } + } +} + + +#[cfg(test)] +mod test { + use prelude::v1::*; + use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; + use cell::RefCell; + use sync::Arc; + use boxed; + use thread; + + #[test] + fn smoke() { + let m = ReentrantMutex::new(()); + { + let a = m.lock().unwrap(); + { + let b = m.lock().unwrap(); + { + let c = m.lock().unwrap(); + assert_eq!(*c, ()); + } + assert_eq!(*b, ()); + } + assert_eq!(*a, ()); + } + } + + #[test] + fn is_mutex() { + let m = ReentrantMutex::new(RefCell::new(0)); + let lock = m.lock().unwrap(); + let handle = thread::scoped(|| { + let lock = m.lock().unwrap(); + assert_eq!(*lock.borrow(), 4950); + }); + for i in 0..100 { + let mut lock = m.lock().unwrap(); + *lock.borrow_mut() += i; + } + drop(lock); + drop(handle); + } + + #[test] + fn trylock_works() { + let m = ReentrantMutex::new(()); + let lock = m.try_lock().unwrap(); + let lock2 = m.try_lock().unwrap(); + { + thread::scoped(|| { + let lock = m.try_lock(); + assert!(lock.is_err()); + }); + } + let lock3 = m.try_lock().unwrap(); + } + + pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); + impl<'a> Drop for Answer<'a> { + fn drop(&mut self) { + *self.0.borrow_mut() = 42; + } + } + + #[test] + fn poison_works() { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + let mc = m.clone(); + let result = thread::spawn(move ||{ + let lock = mc.lock().unwrap(); + *lock.borrow_mut() = 1; + let lock2 = mc.lock().unwrap(); + *lock.borrow_mut() = 2; + let answer = Answer(lock2); + panic!("What the answer to my lifetimes dilemma is?"); + drop(answer); + }).join(); + assert!(result.is_err()); + let r = m.lock().err().unwrap().into_inner(); + assert_eq!(*r.borrow(), 42); + } +} diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs index f7d7a5715b..725a09bcc8 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -21,7 +21,7 @@ pub struct RWLock(imp::RWLock); pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT); impl RWLock { - /// Acquire shared access to the underlying lock, blocking the current + /// Acquires shared access to the underlying lock, blocking the current /// thread to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any @@ -29,7 +29,7 @@ impl RWLock { #[inline] pub unsafe fn read(&self) { self.0.read() } - /// Attempt to acquire shared access to this lock, returning whether it + /// Attempts to acquire shared access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. @@ -39,7 +39,7 @@ impl RWLock { #[inline] pub unsafe fn try_read(&self) -> bool { self.0.try_read() } - /// Acquire write access to the underlying lock, blocking the current thread + /// Acquires write access to the underlying lock, blocking the current thread /// to do so. /// /// Behavior is undefined if the rwlock has been moved between this and any @@ -47,7 +47,7 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { self.0.write() } - /// Attempt to acquire exclusive access to this lock, returning whether it + /// Attempts to acquire exclusive access to this lock, returning whether it /// succeeded or not. /// /// This function does not block the current thread. @@ -57,20 +57,20 @@ impl RWLock { #[inline] pub unsafe fn try_write(&self) -> bool { self.0.try_write() } - /// Unlock previously acquired shared access to this lock. + /// Unlocks previously acquired shared access to this lock. /// /// Behavior is undefined if the current thread does not have shared access. #[inline] pub unsafe fn read_unlock(&self) { self.0.read_unlock() } - /// Unlock previously acquired exclusive access to this lock. + /// Unlocks previously acquired exclusive access to this lock. /// /// Behavior is undefined if the current thread does not currently have /// exclusive access. #[inline] pub unsafe fn write_unlock(&self) { self.0.write_unlock() } - /// Destroy OS-related resources with this RWLock. + /// Destroys OS-related resources with this RWLock. /// /// Behavior is undefined if there are any currently active users of this /// lock. diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index 5995d7ac10..618a389110 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -207,7 +207,7 @@ impl StaticKey { } impl Key { - /// Create a new managed OS TLS key. + /// Creates a new managed OS TLS key. /// /// This key will be deallocated when the key falls out of scope. /// diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 987a12293d..1228243498 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -35,10 +35,8 @@ use borrow::Cow; use cmp; use fmt; use hash::{Hash, Hasher}; -use iter::{FromIterator, IntoIterator}; +use iter::FromIterator; use mem; -#[allow(deprecated)] // Int -use num::Int; use ops; use slice; use str; @@ -69,7 +67,7 @@ impl fmt::Debug for CodePoint { } impl CodePoint { - /// Unsafely create a new `CodePoint` without checking the value. + /// Unsafely creates a new `CodePoint` without checking the value. /// /// Only use when `value` is known to be less than or equal to 0x10FFFF. #[inline] @@ -77,9 +75,9 @@ impl CodePoint { CodePoint { value: value } } - /// Create a new `CodePoint` if the value is a valid code point. + /// Creates a new `CodePoint` if the value is a valid code point. /// - /// Return `None` if `value` is above 0x10FFFF. + /// Returns `None` if `value` is above 0x10FFFF. #[inline] pub fn from_u32(value: u32) -> Option { match value { @@ -88,7 +86,7 @@ impl CodePoint { } } - /// Create a new `CodePoint` from a `char`. + /// Creates a new `CodePoint` from a `char`. /// /// Since all Unicode scalar values are code points, this always succeeds. #[inline] @@ -96,15 +94,15 @@ impl CodePoint { CodePoint { value: value as u32 } } - /// Return the numeric value of the code point. + /// Returns the numeric value of the code point. #[inline] pub fn to_u32(&self) -> u32 { self.value } - /// Optionally return a Unicode scalar value for the code point. + /// Optionally returns a Unicode scalar value for the code point. /// - /// Return `None` if the code point is a surrogate (from U+D800 to U+DFFF). + /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char(&self) -> Option { match self.value { @@ -113,9 +111,9 @@ impl CodePoint { } } - /// Return a Unicode scalar value for the code point. + /// Returns a Unicode scalar value for the code point. /// - /// Return `'\u{FFFD}'` (the replacement character “�”) + /// Returns `'\u{FFFD}'` (the replacement character “�”) /// if the code point is a surrogate (from U+D800 to U+DFFF). #[inline] pub fn to_char_lossy(&self) -> char { @@ -151,19 +149,19 @@ impl fmt::Debug for Wtf8Buf { } impl Wtf8Buf { - /// Create an new, empty WTF-8 string. + /// Creates an new, empty WTF-8 string. #[inline] pub fn new() -> Wtf8Buf { Wtf8Buf { bytes: Vec::new() } } - /// Create an new, empty WTF-8 string with pre-allocated capacity for `n` bytes. + /// Creates an new, empty WTF-8 string with pre-allocated capacity for `n` bytes. #[inline] pub fn with_capacity(n: usize) -> Wtf8Buf { Wtf8Buf { bytes: Vec::with_capacity(n) } } - /// Create a WTF-8 string from an UTF-8 `String`. + /// Creates a WTF-8 string from an UTF-8 `String`. /// /// This takes ownership of the `String` and does not copy. /// @@ -173,7 +171,7 @@ impl Wtf8Buf { Wtf8Buf { bytes: string.into_bytes() } } - /// Create a WTF-8 string from an UTF-8 `&str` slice. + /// Creates a WTF-8 string from an UTF-8 `&str` slice. /// /// This copies the content of the slice. /// @@ -183,7 +181,7 @@ impl Wtf8Buf { Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) } } - /// Create a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. + /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. /// /// This is lossless: calling `.encode_wide()` on the resulting string /// will always return the original code units. @@ -319,7 +317,7 @@ impl Wtf8Buf { self.bytes.truncate(new_len) } - /// Consume the WTF-8 string and try to convert it to UTF-8. + /// Consumes the WTF-8 string and tries to convert it to UTF-8. /// /// This does not copy the data. /// @@ -333,7 +331,7 @@ impl Wtf8Buf { } } - /// Consume the WTF-8 string and convert it lossily to UTF-8. + /// Consumes the WTF-8 string and converts it lossily to UTF-8. /// /// This does not copy the data (but may overwrite parts of it in place). /// @@ -454,7 +452,7 @@ impl fmt::Debug for Wtf8 { } impl Wtf8 { - /// Create a WTF-8 slice from a UTF-8 `&str` slice. + /// Creates a WTF-8 slice from a UTF-8 `&str` slice. /// /// Since WTF-8 is a superset of UTF-8, this always succeeds. #[inline] @@ -462,13 +460,13 @@ impl Wtf8 { unsafe { mem::transmute(value.as_bytes()) } } - /// Return the length, in WTF-8 bytes. + /// Returns the length, in WTF-8 bytes. #[inline] pub fn len(&self) -> usize { self.bytes.len() } - /// Return the code point at `position` if it is in the ASCII range, + /// Returns the code point at `position` if it is in the ASCII range, /// or `b'\xFF' otherwise. /// /// # Panics @@ -482,7 +480,7 @@ impl Wtf8 { } } - /// Return the code point at `position`. + /// Returns the code point at `position`. /// /// # Panics /// @@ -494,7 +492,7 @@ impl Wtf8 { code_point } - /// Return the code point at `position` + /// Returns the code point at `position` /// and the position of the next code point. /// /// # Panics @@ -507,15 +505,15 @@ impl Wtf8 { (CodePoint { value: c }, n) } - /// Return an iterator for the string’s code points. + /// Returns an iterator for the string’s code points. #[inline] pub fn code_points(&self) -> Wtf8CodePoints { Wtf8CodePoints { bytes: self.bytes.iter() } } - /// Try to convert the string to UTF-8 and return a `&str` slice. + /// Tries to convert the string to UTF-8 and return a `&str` slice. /// - /// Return `None` if the string contains surrogates. + /// Returns `None` if the string contains surrogates. /// /// This does not copy the data. #[inline] @@ -528,8 +526,8 @@ impl Wtf8 { } } - /// Lossily convert the string to UTF-8. - /// Return an UTF-8 `&str` slice if the contents are well-formed in UTF-8. + /// Lossily converts the string to UTF-8. + /// Returns an UTF-8 `&str` slice if the contents are well-formed in UTF-8. /// /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”). /// @@ -559,7 +557,7 @@ impl Wtf8 { } } - /// Convert the WTF-8 string to potentially ill-formed UTF-16 + /// Converts the WTF-8 string to potentially ill-formed UTF-16 /// and return an iterator of 16-bit code units. /// /// This is lossless: diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs index 2514d4bf4a..aa4bf82120 100644 --- a/src/libstd/sys/unix/c.rs +++ b/src/libstd/sys/unix/c.rs @@ -26,39 +26,35 @@ use libc; target_os = "dragonfly", target_os = "bitrig", target_os = "openbsd"))] -pub const FIONBIO: libc::c_ulong = 0x8004667e; -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm", - target_arch = "aarch64")), - target_os = "android"))] -pub const FIONBIO: libc::c_ulong = 0x5421; -#[cfg(all(target_os = "linux", - any(target_arch = "mips", - target_arch = "mipsel", - target_arch = "powerpc")))] -pub const FIONBIO: libc::c_ulong = 0x667e; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd"))] -pub const FIOCLEX: libc::c_ulong = 0x20006601; +mod consts { + use libc; + pub const FIONBIO: libc::c_ulong = 0x8004667e; + pub const FIOCLEX: libc::c_ulong = 0x20006601; + pub const FIONCLEX: libc::c_ulong = 0x20006602; +} #[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64")), target_os = "android"))] -pub const FIOCLEX: libc::c_ulong = 0x5451; +mod consts { + use libc; + pub const FIONBIO: libc::c_ulong = 0x5421; + pub const FIOCLEX: libc::c_ulong = 0x5451; + pub const FIONCLEX: libc::c_ulong = 0x5450; +} #[cfg(all(target_os = "linux", any(target_arch = "mips", target_arch = "mipsel", target_arch = "powerpc")))] -pub const FIOCLEX: libc::c_ulong = 0x6601; +mod consts { + use libc; + pub const FIONBIO: libc::c_ulong = 0x667e; + pub const FIOCLEX: libc::c_ulong = 0x6601; + pub const FIONCLEX: libc::c_ulong = 0x6600; +} +pub use self::consts::*; #[cfg(any(target_os = "macos", target_os = "ios", @@ -163,6 +159,8 @@ extern { pub fn utimes(filename: *const libc::c_char, times: *const libc::timeval) -> libc::c_int; pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; + pub fn setgroups(ngroups: libc::c_int, + ptr: *const libc::c_void) -> libc::c_int; } #[cfg(any(target_os = "macos", target_os = "ios"))] @@ -194,12 +192,12 @@ mod select { #[repr(C)] pub struct fd_set { // FIXME: shouldn't this be a c_ulong? - fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS as usize)] + fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)] } pub fn fd_set(set: &mut fd_set, fd: i32) { let fd = fd as usize; - set.fds_bits[fd / usize::BITS as usize] |= 1 << (fd % usize::BITS as usize); + set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS); } } diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 90dfebc4c4..ed6382e000 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -17,7 +17,6 @@ use sys::mutex::{self, Mutex}; use sys::time; use sys::sync as ffi; use time::Duration; -use num::{Int, NumCast}; pub struct Condvar { inner: UnsafeCell } @@ -70,8 +69,8 @@ impl Condvar { let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut()); debug_assert_eq!(r, 0); - let seconds = NumCast::from(dur.num_seconds()); - let timeout = match seconds.and_then(|s| sys_now.tv_sec.checked_add(s)) { + let seconds = dur.num_seconds() as libc::time_t; + let timeout = match sys_now.tv_sec.checked_add(seconds) { Some(sec) => { libc::timespec { tv_sec: sec, @@ -81,7 +80,7 @@ impl Condvar { } None => { libc::timespec { - tv_sec: Int::max_value(), + tv_sec: ::max_value(), tv_nsec: 1_000_000_000 - 1, } } diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index fbfbb40701..032fd33b1d 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -15,14 +15,12 @@ //! //! # Example //! -//! ```rust,ignore -//! #![feature(globs)] -//! -//! use std::old_io::fs::File; +//! ```no_run +//! use std::fs::File; //! use std::os::unix::prelude::*; //! //! fn main() { -//! let f = File::create(&Path::new("foo.txt")).unwrap(); +//! let f = File::create("foo.txt").unwrap(); //! let fd = f.as_raw_fd(); //! //! // use fd with native unix bindings @@ -34,7 +32,6 @@ /// Unix-specific extensions to general I/O primitives #[stable(feature = "rust1", since = "1.0.0")] pub mod io { - #[allow(deprecated)] use old_io; use fs; use libc; use net; @@ -53,7 +50,7 @@ pub mod io { /// and `AsRawSocket` set of traits. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { - /// Extract the raw file descriptor. + /// Extracts the raw file descriptor. /// /// This method does **not** pass ownership of the raw file descriptor /// to the caller. The descriptor is only guarantee to be valid while @@ -74,17 +71,12 @@ pub mod io { /// descriptor. The returned object will take responsibility for closing /// it when the object goes out of scope. /// - /// Callers should normally only pass in a valid file descriptor to this - /// method or otherwise methods will return errors. - fn from_raw_fd(fd: RawFd) -> Self; - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; } #[stable(feature = "rust1", since = "1.0.0")] @@ -95,75 +87,11 @@ pub mod io { } #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawFd for fs::File { - fn from_raw_fd(fd: RawFd) -> fs::File { + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { fs::File::from_inner(sys::fs2::File::from_inner(fd)) } } - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::pipe::PipeStream { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::net::pipe::UnixStream { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::net::pipe::UnixListener { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::net::pipe::UnixAcceptor { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl AsRawFd for old_io::net::tcp::TcpStream { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl AsRawFd for old_io::net::tcp::TcpListener { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - #[allow(deprecated)] - impl AsRawFd for old_io::net::tcp::TcpAcceptor { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - - #[allow(deprecated)] - #[stable(feature = "rust1", since = "1.0.0")] - impl AsRawFd for old_io::net::udp::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd() - } - } - #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for net::TcpStream { fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() } @@ -179,21 +107,21 @@ pub mod io { #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawFd for net::TcpStream { - fn from_raw_fd(fd: RawFd) -> net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { let socket = sys::net::Socket::from_inner(fd); net::TcpStream::from_inner(net2::TcpStream::from_inner(socket)) } } #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawFd for net::TcpListener { - fn from_raw_fd(fd: RawFd) -> net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { let socket = sys::net::Socket::from_inner(fd); net::TcpListener::from_inner(net2::TcpListener::from_inner(socket)) } } #[unstable(feature = "from_raw_os", reason = "trait is unstable")] impl FromRawFd for net::UdpSocket { - fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { let socket = sys::net::Socket::from_inner(fd); net::UdpSocket::from_inner(net2::UdpSocket::from_inner(socket)) } @@ -216,11 +144,11 @@ pub mod ffi { /// Unix-specific extensions to `OsString`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { - /// Create an `OsString` from a byte vector. + /// Creates an `OsString` from a byte vector. #[stable(feature = "rust1", since = "1.0.0")] fn from_vec(vec: Vec) -> Self; - /// Yield the underlying byte vector of this `OsString`. + /// Yields the underlying byte vector of this `OsString`. #[stable(feature = "rust1", since = "1.0.0")] fn into_vec(self) -> Vec; } @@ -241,7 +169,7 @@ pub mod ffi { #[stable(feature = "rust1", since = "1.0.0")] fn from_bytes(slice: &[u8]) -> &Self; - /// Get the underlying byte view of the `OsStr` slice. + /// Gets the underlying byte view of the `OsStr` slice. #[stable(feature = "rust1", since = "1.0.0")] fn as_bytes(&self) -> &[u8]; } @@ -280,7 +208,7 @@ pub mod fs { /// Unix-specific extensions to `OpenOptions` pub trait OpenOptionsExt { - /// Set the mode bits that a new file will be created with. + /// Sets the mode bits that a new file will be created with. /// /// If a new file is created as part of a `File::open_opts` call then this /// specified `mode` will be used as the permission bits for the new file. diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index f7c57c3f5e..e5bdb55435 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -13,6 +13,7 @@ use core::prelude::*; use io; use libc::{self, c_int, size_t, c_void}; use mem; +use sys::c; use sys::cvt; use sys_common::AsInner; @@ -27,7 +28,7 @@ impl FileDesc { pub fn raw(&self) -> c_int { self.fd } - /// Extract the actual filedescriptor without closing it. + /// Extracts the actual filedescriptor without closing it. pub fn into_raw(self) -> c_int { let fd = self.fd; unsafe { mem::forget(self) }; @@ -51,6 +52,13 @@ impl FileDesc { })); Ok(ret as usize) } + + pub fn set_cloexec(&self) { + unsafe { + let ret = c::ioctl(self.fd, c::FIOCLEX); + debug_assert_eq!(ret, 0); + } + } } impl AsInner for FileDesc { @@ -59,14 +67,11 @@ impl AsInner for FileDesc { impl Drop for FileDesc { fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.fd > libc::STDERR_FILENO { - let _ = unsafe { libc::close(self.fd) }; - } + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // (opened after we closed ours. + let _ = unsafe { libc::close(self.fd) }; } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs deleted file mode 100644 index 6b085c8eb7..0000000000 --- a/src/libstd/sys/unix/fs.rs +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright 2013-2014 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. - -//! Blocking posix-based file I/O -#![allow(deprecated)] - -#![allow(deprecated)] // this module itself is essentially deprecated - -use prelude::v1::*; - -use ffi::{CString, CStr}; -use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; -use old_io::{IoResult, FileStat, SeekStyle}; -use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; -use old_io; -use old_path::{Path, GenericPath}; -use libc::{self, c_int, c_void}; -use mem; -use ptr; -use sys::retry; -use sys_common::{keep_going, eof, mkerr_libc}; - -pub type fd_t = libc::c_int; - -pub struct FileDesc { - /// The underlying C file descriptor. - fd: fd_t, - - /// Whether to close the file descriptor on drop. - close_on_drop: bool, -} - -impl FileDesc { - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { fd: fd, close_on_drop: close_on_drop } - } - - pub fn read(&self, buf: &mut [u8]) -> IoResult { - let ret = retry(|| unsafe { - libc::read(self.fd(), - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as libc::size_t) - }); - if ret == 0 { - Err(eof()) - } else if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as usize) - } - } - pub fn write(&self, buf: &[u8]) -> IoResult<()> { - let ret = keep_going(buf, |buf, len| { - unsafe { - libc::write(self.fd(), buf as *const libc::c_void, - len as libc::size_t) as i64 - } - }); - if ret < 0 { - Err(super::last_error()) - } else { - Ok(()) - } - } - - pub fn fd(&self) -> fd_t { self.fd } - - pub fn seek(&self, pos: i64, whence: SeekStyle) -> IoResult { - let whence = match whence { - SeekSet => libc::SEEK_SET, - SeekEnd => libc::SEEK_END, - SeekCur => libc::SEEK_CUR, - }; - let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } - } - - pub fn tell(&self) -> IoResult { - let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } - } - - pub fn fsync(&self) -> IoResult<()> { - mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) })) - } - - pub fn datasync(&self) -> IoResult<()> { - return mkerr_libc(os_datasync(self.fd())); - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn os_datasync(fd: c_int) -> c_int { - unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) } - } - #[cfg(target_os = "linux")] - fn os_datasync(fd: c_int) -> c_int { - retry(|| unsafe { libc::fdatasync(fd) }) - } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] - fn os_datasync(fd: c_int) -> c_int { - retry(|| unsafe { libc::fsync(fd) }) - } - } - - pub fn truncate(&self, offset: i64) -> IoResult<()> { - mkerr_libc(retry(|| unsafe { - libc::ftruncate(self.fd(), offset as libc::off_t) - })) - } - - pub fn fstat(&self) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::fstat(self.fd(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - } - - /// Extract the actual filedescriptor without closing it. - pub fn unwrap(self) -> fd_t { - let fd = self.fd; - unsafe { mem::forget(self) }; - fd - } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.close_on_drop && self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, self.fd); - } - } - } -} - -fn cstr(path: &Path) -> IoResult { - Ok(try!(CString::new(path.as_vec()))) -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { - let flags = match fm { - Open => 0, - Append => libc::O_APPEND, - Truncate => libc::O_TRUNC, - }; - // Opening with a write permission must silently create the file. - let (flags, mode) = match fa { - Read => (flags | libc::O_RDONLY, 0), - Write => (flags | libc::O_WRONLY | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - }; - - let path = try!(cstr(path)); - match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { - -1 => Err(super::last_error()), - fd => Ok(FileDesc::new(fd, true)), - } -} - -pub fn mkdir(p: &Path, mode: usize) -> IoResult<()> { - let p = try!(cstr(p)); - mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) -} - -pub fn readdir(p: &Path) -> IoResult> { - use libc::{dirent_t}; - use libc::{opendir, readdir_r, closedir}; - - fn prune(root: &CString, dirs: Vec) -> Vec { - let root = Path::new(root); - - dirs.into_iter().filter(|path| { - path.as_vec() != b"." && path.as_vec() != b".." - }).map(|path| root.join(path)).collect() - } - - extern { - fn rust_dirent_t_size() -> libc::c_int; - fn rust_list_dir_val(ptr: *mut dirent_t) -> *const libc::c_char; - } - - let size = unsafe { rust_dirent_t_size() }; - let mut buf = Vec::::with_capacity(size as usize); - let ptr = buf.as_mut_ptr() as *mut dirent_t; - - let p = try!(CString::new(p.as_vec())); - let dir_ptr = unsafe {opendir(p.as_ptr())}; - - if dir_ptr as usize != 0 { - let mut paths = vec!(); - let mut entry_ptr = ptr::null_mut(); - while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { - if entry_ptr.is_null() { break } - paths.push(unsafe { - Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes()) - }); - } - assert_eq!(unsafe { closedir(dir_ptr) }, 0); - Ok(prune(&p, paths)) - } else { - Err(super::last_error()) - } -} - -pub fn unlink(p: &Path) -> IoResult<()> { - let p = try!(cstr(p)); - mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) -} - -pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = try!(cstr(old)); - let new = try!(cstr(new)); - mkerr_libc(unsafe { - libc::rename(old.as_ptr(), new.as_ptr()) - }) -} - -pub fn chmod(p: &Path, mode: usize) -> IoResult<()> { - let p = try!(cstr(p)); - mkerr_libc(retry(|| unsafe { - libc::chmod(p.as_ptr(), mode as libc::mode_t) - })) -} - -pub fn rmdir(p: &Path) -> IoResult<()> { - let p = try!(cstr(p)); - mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) -} - -pub fn chown(p: &Path, uid: isize, gid: isize) -> IoResult<()> { - let p = try!(cstr(p)); - mkerr_libc(retry(|| unsafe { - libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) - })) -} - -pub fn readlink(p: &Path) -> IoResult { - let c_path = try!(cstr(p)); - let p = c_path.as_ptr(); - let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; - if len == -1 { - len = 1024; // FIXME: read PATH_MAX from C ffi? - } - let mut buf: Vec = Vec::with_capacity(len as usize); - match unsafe { - libc::readlink(p, buf.as_ptr() as *mut libc::c_char, - len as libc::size_t) as libc::c_int - } { - -1 => Err(super::last_error()), - n => { - assert!(n > 0); - unsafe { buf.set_len(n as usize); } - Ok(Path::new(buf)) - } - } -} - -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = try!(cstr(src)); - let dst = try!(cstr(dst)); - mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) -} - -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = try!(cstr(src)); - let dst = try!(cstr(dst)); - mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) -} - -fn mkstat(stat: &libc::stat) -> FileStat { - // FileStat times are in milliseconds - fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } - - fn ctime(stat: &libc::stat) -> u64 { - mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64) - } - - fn atime(stat: &libc::stat) -> u64 { - mktime(stat.st_atime as u64, stat.st_atime_nsec as u64) - } - - fn mtime(stat: &libc::stat) -> u64 { - mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64) - } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 } - #[cfg(any(target_os = "linux", target_os = "android"))] - fn flags(_stat: &libc::stat) -> u64 { 0 } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 } - #[cfg(any(target_os = "linux", target_os = "android"))] - fn gen(_stat: &libc::stat) -> u64 { 0 } - - FileStat { - size: stat.st_size as u64, - kind: match (stat.st_mode as libc::mode_t) & libc::S_IFMT { - libc::S_IFREG => old_io::FileType::RegularFile, - libc::S_IFDIR => old_io::FileType::Directory, - libc::S_IFIFO => old_io::FileType::NamedPipe, - libc::S_IFBLK => old_io::FileType::BlockSpecial, - libc::S_IFLNK => old_io::FileType::Symlink, - _ => old_io::FileType::Unknown, - }, - perm: FilePermission::from_bits_truncate(stat.st_mode as u32), - created: ctime(stat), - modified: mtime(stat), - accessed: atime(stat), - unstable: UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: stat.st_blksize as u64, - blocks: stat.st_blocks as u64, - flags: flags(stat), - gen: gen(stat), - }, - } -} - -pub fn stat(p: &Path) -> IoResult { - let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::stat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -pub fn lstat(p: &Path) -> IoResult { - let p = try!(cstr(p)); - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = try!(cstr(p)); - let buf = libc::utimbuf { - actime: (atime / 1000) as libc::time_t, - modtime: (mtime / 1000) as libc::time_t, - }; - mkerr_libc(unsafe { libc::utime(p.as_ptr(), &buf) }) -} - -#[cfg(test)] -mod tests { - use super::FileDesc; - use libc; - use os; - use prelude::v1::*; - - #[cfg_attr(any(target_os = "freebsd", - target_os = "openbsd"), - ignore)] - // under some system, pipe(2) will return a bidrectionnal pipe - #[test] - fn test_file_desc() { - // Run this test with some pipes so we don't have to mess around with - // opening or closing files. - let (mut reader, mut writer) = unsafe { ::sys::os::pipe().unwrap() }; - - writer.write(b"test").unwrap(); - let mut buf = [0; 4]; - match reader.read(&mut buf) { - Ok(4) => { - assert_eq!(buf[0], 't' as u8); - assert_eq!(buf[1], 'e' as u8); - assert_eq!(buf[2], 's' as u8); - assert_eq!(buf[3], 't' as u8); - } - r => panic!("invalid read: {:?}", r), - } - - assert!(writer.read(&mut buf).is_err()); - assert!(reader.write(&buf).is_err()); - } -} diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index c0426af051..ac121f1c82 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -205,19 +205,27 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let path = try!(cstr(path)); + File::open_c(&path, opts) + } + + pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { let flags = opts.flags | match (opts.read, opts.write) { (true, true) => libc::O_RDWR, (false, true) => libc::O_WRONLY, (true, false) | (false, false) => libc::O_RDONLY, }; - let path = try!(cstr(path)); let fd = try!(cvt_r(|| unsafe { libc::open(path.as_ptr(), flags, opts.mode) })); - Ok(File(FileDesc::new(fd))) + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Ok(File(fd)) } + pub fn into_fd(self) -> FileDesc { self.0 } + pub fn file_attr(&self) -> io::Result { let mut stat: libc::stat = unsafe { mem::zeroed() }; try!(cvt(unsafe { libc::fstat(self.0.raw(), &mut stat) })); diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index e8409bb4fd..d99753a6a4 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -13,124 +13,31 @@ use prelude::v1::*; -use ffi::CStr; use io::{self, ErrorKind}; use libc; -use num::{Int, SignedInt}; -use old_io::{self, IoError}; -use str; -use sys_common::mkerr_libc; +use num::One; +use ops::Neg; pub mod backtrace; pub mod c; pub mod condvar; pub mod ext; pub mod fd; -pub mod fs; // support for std::old_io -pub mod fs2; // support for std::fs -pub mod helper_signal; +pub mod fs2; pub mod mutex; pub mod net; pub mod os; pub mod os_str; -pub mod pipe; pub mod pipe2; -pub mod process; pub mod process2; pub mod rwlock; pub mod stack_overflow; pub mod sync; -pub mod tcp; pub mod thread; pub mod thread_local; pub mod time; -pub mod timer; -pub mod tty; -pub mod udp; pub mod stdio; -pub mod addrinfo { - pub use sys_common::net::get_host_addresses; - pub use sys_common::net::get_address_name; -} - -// FIXME: move these to c module -pub type sock_t = self::fs::fd_t; -pub type wrlen = libc::size_t; -pub type msglen_t = libc::size_t; -pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); } - -#[allow(deprecated)] -pub fn last_error() -> IoError { - decode_error_detailed(os::errno() as i32) -} - -#[allow(deprecated)] -pub fn last_net_error() -> IoError { - last_error() -} - -extern "system" { - fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; -} - -#[allow(deprecated)] -pub fn last_gai_error(s: libc::c_int) -> IoError { - - let mut err = decode_error(s); - err.detail = Some(unsafe { - let data = CStr::from_ptr(gai_strerror(s)); - str::from_utf8(data.to_bytes()).unwrap().to_string() - }); - err -} - -/// Convert an `errno` value into a high-level error variant and description. -#[allow(deprecated)] -pub fn decode_error(errno: i32) -> IoError { - // FIXME: this should probably be a bit more descriptive... - let (kind, desc) = match errno { - libc::EOF => (old_io::EndOfFile, "end of file"), - libc::ECONNREFUSED => (old_io::ConnectionRefused, "connection refused"), - libc::ECONNRESET => (old_io::ConnectionReset, "connection reset"), - libc::EPERM | libc::EACCES => - (old_io::PermissionDenied, "permission denied"), - libc::EPIPE => (old_io::BrokenPipe, "broken pipe"), - libc::ENOTCONN => (old_io::NotConnected, "not connected"), - libc::ECONNABORTED => (old_io::ConnectionAborted, "connection aborted"), - libc::EADDRNOTAVAIL => (old_io::ConnectionRefused, "address not available"), - libc::EADDRINUSE => (old_io::ConnectionRefused, "address in use"), - libc::ENOENT => (old_io::FileNotFound, "no such file or directory"), - libc::EISDIR => (old_io::InvalidInput, "illegal operation on a directory"), - libc::ENOSYS => (old_io::IoUnavailable, "function not implemented"), - libc::EINVAL => (old_io::InvalidInput, "invalid argument"), - libc::ENOTTY => - (old_io::MismatchedFileTypeForOperation, - "file descriptor is not a TTY"), - libc::ETIMEDOUT => (old_io::TimedOut, "operation timed out"), - libc::ECANCELED => (old_io::TimedOut, "operation aborted"), - libc::consts::os::posix88::EEXIST => - (old_io::PathAlreadyExists, "path already exists"), - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => - (old_io::ResourceUnavailable, "resource temporarily unavailable"), - - _ => (old_io::OtherIoError, "unknown error") - }; - IoError { kind: kind, desc: desc, detail: None } -} - -#[allow(deprecated)] -pub fn decode_error_detailed(errno: i32) -> IoError { - let mut err = decode_error(errno); - err.detail = Some(os::error_string(errno)); - err -} - -#[allow(deprecated)] pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno as libc::c_int { libc::ECONNREFUSED => ErrorKind::ConnectionRefused, @@ -157,23 +64,8 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } -#[inline] -#[allow(deprecated)] -pub fn retry (mut f: F) -> T where - T: SignedInt, - F: FnMut() -> T, -{ - let one: T = Int::one(); - loop { - let n = f(); - if n == -one && os::errno() == libc::EINTR as i32 { } - else { return n } - } -} - -#[allow(deprecated)] -pub fn cvt(t: T) -> io::Result { - let one: T = Int::one(); +pub fn cvt>(t: T) -> io::Result { + let one: T = T::one(); if t == -one { Err(io::Error::last_os_error()) } else { @@ -183,7 +75,7 @@ pub fn cvt(t: T) -> io::Result { #[allow(deprecated)] pub fn cvt_r(mut f: F) -> io::Result - where T: SignedInt, F: FnMut() -> T + where T: One + PartialEq + Neg, F: FnMut() -> T { loop { match cvt(f()) { @@ -199,18 +91,3 @@ pub fn ms_to_timeval(ms: u64) -> libc::timeval { tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t, } } - -#[allow(deprecated)] -pub fn wouldblock() -> bool { - let err = os::errno(); - err == libc::EWOULDBLOCK as i32 || err == libc::EAGAIN as i32 -} - -#[allow(deprecated)] -pub fn set_nonblocking(fd: sock_t, nb: bool) { - let set = nb as libc::c_int; - mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })).unwrap(); -} - -// nothing needed on unix platforms -pub fn init_net() {} diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 1c0ce29380..af814653c1 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use cell::UnsafeCell; use sys::sync as ffi; +use mem; pub struct Mutex { inner: UnsafeCell } @@ -67,3 +68,50 @@ impl Mutex { debug_assert!(r == 0 || r == libc::EINVAL); } } + +// FIXME: remove the box, because box happens twice now, once at the common layer and once here. +// Box is necessary here, because mutex may not change address after it is intialised on some +// platforms. Regular Mutex above handles this by offloading intialisation to the OS on first lock. +// Sadly, as far as reentrant mutexes go, this scheme is not quite portable and we must initialise +// when we create the mutex, in the `new`. +pub struct ReentrantMutex { inner: Box> } + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub unsafe fn new() -> ReentrantMutex { + let mutex = ReentrantMutex { inner: box mem::uninitialized() }; + let mut attr: ffi::pthread_mutexattr_t = mem::uninitialized(); + let result = ffi::pthread_mutexattr_init(&mut attr as *mut _); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutexattr_settype(&mut attr as *mut _, + ffi::PTHREAD_MUTEX_RECURSIVE); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutex_init(mutex.inner.get(), &attr as *const _); + debug_assert_eq!(result, 0); + let result = ffi::pthread_mutexattr_destroy(&mut attr as *mut _); + debug_assert_eq!(result, 0); + mutex + } + + pub unsafe fn lock(&self) { + let result = ffi::pthread_mutex_lock(self.inner.get()); + debug_assert_eq!(result, 0); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + ffi::pthread_mutex_trylock(self.inner.get()) == 0 + } + + pub unsafe fn unlock(&self) { + let result = ffi::pthread_mutex_unlock(self.inner.get()); + debug_assert_eq!(result, 0); + } + + pub unsafe fn destroy(&self) { + let result = ffi::pthread_mutex_destroy(self.inner.get()); + debug_assert_eq!(result, 0); + } +} diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 908136a42a..2e1cbb2a1e 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -47,7 +47,9 @@ impl Socket { }; unsafe { let fd = try!(cvt(libc::socket(fam, ty, 0))); - Ok(Socket(FileDesc::new(fd))) + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Ok(Socket(fd)) } } @@ -56,13 +58,16 @@ impl Socket { let fd = try!(cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })); - Ok(Socket(FileDesc::new(fd))) + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Ok(Socket(fd)) } pub fn duplicate(&self) -> io::Result { - cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| { - Socket(FileDesc::new(fd)) - }) + let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) })); + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Ok(Socket(fd)) } pub fn read(&self, buf: &mut [u8]) -> io::Result { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index d2220bdec3..5919502abd 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -22,14 +22,12 @@ use io; use iter; use libc::{self, c_int, c_char, c_void}; use mem; -#[allow(deprecated)] use old_io::{IoError, IoResult}; use ptr; use path::{self, PathBuf}; use slice; use str; use sys::c; use sys::fd; -use sys::fs::FileDesc; use vec; const BUF_BYTES: usize = 2048; @@ -86,7 +84,7 @@ pub fn errno() -> i32 { } } -/// Get a detailed string description for the given error number +/// Gets a detailed string description for the given error number. pub fn error_string(errno: i32) -> String { #[cfg(target_os = "linux")] extern { @@ -448,16 +446,6 @@ pub fn unsetenv(n: &OsStr) { } } -#[allow(deprecated)] -pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { - let mut fds = [0; 2]; - if libc::pipe(fds.as_mut_ptr()) == 0 { - Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) - } else { - Err(IoError::last_error()) - } -} - pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs deleted file mode 100644 index f0071295bf..0000000000 --- a/src/libstd/sys/unix/pipe.rs +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright 2014 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. - -#![allow(deprecated)] - -use prelude::v1::*; - -use ffi::CString; -use libc; -use mem; -use sync::{Arc, Mutex}; -use sync::atomic::{AtomicBool, Ordering}; -use old_io::{self, IoResult, IoError}; - -use sys::{self, timer, retry, c, set_nonblocking, wouldblock}; -use sys::fs::{fd_t, FileDesc}; -use sys_common::net::*; -use sys_common::net::SocketStatus::*; -use sys_common::{eof, mkerr_libc}; - -fn unix_socket(ty: libc::c_int) -> IoResult { - match unsafe { libc::socket(libc::AF_UNIX, ty, 0) } { - -1 => Err(super::last_error()), - fd => Ok(fd) - } -} - -fn addr_to_sockaddr_un(addr: &CString, - storage: &mut libc::sockaddr_storage) - -> IoResult { - // the sun_path length is limited to SUN_LEN (with null) - assert!(mem::size_of::() >= - mem::size_of::()); - let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) }; - - let len = addr.as_bytes().len(); - if len > s.sun_path.len() - 1 { - return Err(IoError { - kind: old_io::InvalidInput, - desc: "invalid argument: path must be smaller than SUN_LEN", - detail: None, - }) - } - s.sun_family = libc::AF_UNIX as libc::sa_family_t; - for (slot, value) in s.sun_path.iter_mut().zip(addr.as_bytes().iter()) { - *slot = *value as libc::c_char; - } - - // count the null terminator - let len = mem::size_of::() + len + 1; - return Ok(len as libc::socklen_t); -} - -struct Inner { - fd: fd_t, - - // Unused on Linux, where this lock is not necessary. - #[allow(dead_code)] - lock: Mutex<()>, -} - -impl Inner { - fn new(fd: fd_t) -> Inner { - Inner { fd: fd, lock: Mutex::new(()) } - } -} - -impl Drop for Inner { - fn drop(&mut self) { unsafe { let _ = libc::close(self.fd); } } -} - -fn connect(addr: &CString, ty: libc::c_int, - timeout: Option) -> IoResult { - let mut storage = unsafe { mem::zeroed() }; - let len = try!(addr_to_sockaddr_un(addr, &mut storage)); - let inner = Inner::new(try!(unix_socket(ty))); - let addrp = &storage as *const _ as *const libc::sockaddr; - - match timeout { - None => { - match retry(|| unsafe { libc::connect(inner.fd, addrp, len) }) { - -1 => Err(super::last_error()), - _ => Ok(inner) - } - } - Some(timeout_ms) => { - try!(connect_timeout(inner.fd, addrp, len, timeout_ms)); - Ok(inner) - } - } -} - -fn bind(addr: &CString, ty: libc::c_int) -> IoResult { - let mut storage = unsafe { mem::zeroed() }; - let len = try!(addr_to_sockaddr_un(addr, &mut storage)); - let inner = Inner::new(try!(unix_socket(ty))); - let addrp = &storage as *const _ as *const libc::sockaddr; - match unsafe { - libc::bind(inner.fd, addrp, len) - } { - -1 => Err(super::last_error()), - _ => Ok(inner) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixStream { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - pub fn connect(addr: &CString, - timeout: Option) -> IoResult { - connect(addr, libc::SOCK_STREAM, timeout).map(|inner| { - UnixStream::new(Arc::new(inner)) - }) - } - - fn new(inner: Arc) -> UnixStream { - UnixStream { - inner: inner, - read_deadline: 0, - write_deadline: 0, - } - } - - pub fn fd(&self) -> fd_t { self.inner.fd } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) {} - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { - let ret = Guard { - fd: self.fd(), - guard: self.inner.lock.lock().unwrap(), - }; - set_nonblocking(self.fd(), true); - ret - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let doread = |nb| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::recv(fd, - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as libc::size_t, - flags) as libc::c_int - }; - read(fd, self.read_deadline, dolock, doread) - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let dowrite = |nb: bool, buf: *const u8, len: usize| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::send(fd, - buf as *const _, - len as libc::size_t, - flags) as i64 - }; - match write(fd, self.write_deadline, buf, true, dolock, dowrite) { - Ok(_) => Ok(()), - Err(e) => Err(e) - } - } - - pub fn close_write(&mut self) -> IoResult<()> { - mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_WR) }) - } - - pub fn close_read(&mut self) -> IoResult<()> { - mkerr_libc(unsafe { libc::shutdown(self.fd(), libc::SHUT_RD) }) - } - - pub fn set_timeout(&mut self, timeout: Option) { - let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - self.read_deadline = deadline; - self.write_deadline = deadline; - } - - pub fn set_read_timeout(&mut self, timeout: Option) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn set_write_timeout(&mut self, timeout: Option) { - self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { - UnixStream::new(self.inner.clone()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Listener -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixListener { - inner: Inner, - path: CString, -} - -// we currently own the CString, so these impls should be safe -unsafe impl Send for UnixListener {} -unsafe impl Sync for UnixListener {} - -impl UnixListener { - pub fn bind(addr: &CString) -> IoResult { - bind(addr, libc::SOCK_STREAM).map(|fd| { - UnixListener { inner: fd, path: addr.clone() } - }) - } - - pub fn fd(&self) -> fd_t { self.inner.fd } - - pub fn listen(self) -> IoResult { - match unsafe { libc::listen(self.fd(), 128) } { - -1 => Err(super::last_error()), - - _ => { - let (reader, writer) = try!(unsafe { sys::os::pipe() }); - set_nonblocking(reader.fd(), true); - set_nonblocking(writer.fd(), true); - set_nonblocking(self.fd(), true); - Ok(UnixAcceptor { - inner: Arc::new(AcceptorInner { - listener: self, - reader: reader, - writer: writer, - closed: AtomicBool::new(false), - }), - deadline: 0, - }) - } - } - } -} - -pub struct UnixAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: UnixListener, - reader: FileDesc, - writer: FileDesc, - closed: AtomicBool, -} - -impl UnixAcceptor { - pub fn fd(&self) -> fd_t { self.inner.listener.fd() } - - pub fn accept(&mut self) -> IoResult { - let deadline = if self.deadline == 0 {None} else {Some(self.deadline)}; - - while !self.inner.closed.load(Ordering::SeqCst) { - unsafe { - let mut storage: libc::sockaddr_storage = mem::zeroed(); - let storagep = &mut storage as *mut libc::sockaddr_storage; - let size = mem::size_of::(); - let mut size = size as libc::socklen_t; - match retry(|| { - libc::accept(self.fd(), - storagep as *mut libc::sockaddr, - &mut size as *mut libc::socklen_t) as libc::c_int - }) { - -1 if wouldblock() => {} - -1 => return Err(super::last_error()), - fd => return Ok(UnixStream::new(Arc::new(Inner::new(fd)))), - } - } - try!(await(&[self.fd(), self.inner.reader.fd()], - deadline, Readable)); - } - - Err(eof()) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, Ordering::SeqCst); - let fd = FileDesc::new(self.inner.writer.fd(), false); - match fd.write(&[0]) { - Ok(..) => Ok(()), - Err(..) if wouldblock() => Ok(()), - Err(e) => Err(e), - } - } -} - -impl Clone for UnixAcceptor { - fn clone(&self) -> UnixAcceptor { - UnixAcceptor { inner: self.inner.clone(), deadline: 0 } - } -} - -impl Drop for UnixListener { - fn drop(&mut self) { - // Unlink the path to the socket to ensure that it doesn't linger. We're - // careful to unlink the path before we close the file descriptor to - // prevent races where we unlink someone else's path. - unsafe { - let _ = libc::unlink(self.path.as_ptr()); - } - } -} diff --git a/src/libstd/sys/unix/pipe2.rs b/src/libstd/sys/unix/pipe2.rs index 7af2c0f0b2..e9d8c69fef 100644 --- a/src/libstd/sys/unix/pipe2.rs +++ b/src/libstd/sys/unix/pipe2.rs @@ -20,11 +20,10 @@ use libc; pub struct AnonPipe(FileDesc); -pub unsafe fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { let mut fds = [0; 2]; - if libc::pipe(fds.as_mut_ptr()) == 0 { - Ok((AnonPipe::from_fd(fds[0]), - AnonPipe::from_fd(fds[1]))) + if unsafe { libc::pipe(fds.as_mut_ptr()) == 0 } { + Ok((AnonPipe::from_fd(fds[0]), AnonPipe::from_fd(fds[1]))) } else { Err(io::Error::last_os_error()) } @@ -32,7 +31,9 @@ pub unsafe fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { impl AnonPipe { pub fn from_fd(fd: libc::c_int) -> AnonPipe { - AnonPipe(FileDesc::new(fd)) + let fd = FileDesc::new(fd); + fd.set_cloexec(); + AnonPipe(fd) } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -43,7 +44,7 @@ impl AnonPipe { self.0.write(buf) } - pub fn raw(&self) -> libc::c_int { - self.0.raw() + pub fn into_fd(self) -> FileDesc { + self.0 } } diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs deleted file mode 100644 index 8095325f83..0000000000 --- a/src/libstd/sys/unix/process.rs +++ /dev/null @@ -1,627 +0,0 @@ -// 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. -// -// 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. - -#![allow(deprecated)] // this module itself is essentially deprecated - -use prelude::v1::*; -use self::Req::*; - -use collections::HashMap; -use ffi::CString; -use hash::Hash; -use old_io::process::{ProcessExit, ExitStatus, ExitSignal}; -use old_io::{IoResult, EndOfFile}; -use libc::{self, pid_t, c_void, c_int}; -use io; -use mem; -use sys::os; -use old_path::BytesContainer; -use ptr; -use sync::mpsc::{channel, Sender, Receiver}; -use sys::fs::FileDesc; -use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval}; -use sys_common::helper_thread::Helper; -use sys_common::{AsInner, mkerr_libc, timeout}; - -pub use sys_common::ProcessConfig; - -helper_init! { static HELPER: Helper } - -/// The unique id of the process (this should never be negative). -pub struct Process { - pub pid: pid_t -} - -enum Req { - NewChild(libc::pid_t, Sender, u64), -} - -const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; - -impl Process { - pub fn id(&self) -> pid_t { - self.pid - } - - pub unsafe fn kill(&self, signal: isize) -> IoResult<()> { - Process::killpid(self.pid, signal) - } - - pub unsafe fn killpid(pid: pid_t, signal: isize) -> IoResult<()> { - let r = libc::funcs::posix88::signal::kill(pid, signal as c_int); - mkerr_libc(r) - } - - pub fn spawn(cfg: &C, in_fd: Option